Merge "Add unit tests for class loader context."
diff --git a/Android.bp b/Android.bp
index 3075d67..4d69877 100644
--- a/Android.bp
+++ b/Android.bp
@@ -47,6 +47,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     ramdisk_available: true,
+    vendor_ramdisk_available: true,
     recovery_available: true,
     native_bridge_supported: true,
 
@@ -94,6 +95,7 @@
     defaults: ["linux_bionic_supported"],
     vendor_available: true,
     ramdisk_available: true,
+    vendor_ramdisk_available: true,
     recovery_available: true,
     native_bridge_supported: true,
     sdk_version: "current",
diff --git a/android/apex.go b/android/apex.go
index 3039e79..e70ec4f 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -67,6 +67,15 @@
 	return i.ApexVariationName == ""
 }
 
+func (i ApexInfo) InApex(apex string) bool {
+	for _, a := range i.InApexes {
+		if a == apex {
+			return true
+		}
+	}
+	return false
+}
+
 // ApexTestForInfo stores the contents of APEXes for which this module is a test and thus has
 // access to APEX internals.
 type ApexTestForInfo struct {
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 210d67a8..c87a945 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -29,10 +29,16 @@
 	"github.com/google/blueprint/bootstrap"
 )
 
+type CqueryRequestType int
+
+const (
+	getAllFiles CqueryRequestType = iota
+)
+
 // Map key to describe bazel cquery requests.
 type cqueryKey struct {
-	label        string
-	starlarkExpr string
+	label       string
+	requestType CqueryRequestType
 }
 
 type BazelContext interface {
@@ -61,6 +67,7 @@
 	bazelPath    string
 	outputBase   string
 	workspaceDir string
+	buildDir     string
 
 	requests     map[cqueryKey]bool // cquery requests that have not yet been issued to Bazel
 	requestMutex sync.Mutex         // requests can be written in parallel
@@ -96,8 +103,7 @@
 var _ BazelContext = MockBazelContext{}
 
 func (bazelCtx *bazelContext) GetAllFiles(label string) ([]string, bool) {
-	starlarkExpr := "', '.join([f.path for f in target.files.to_list()])"
-	result, ok := bazelCtx.cquery(label, starlarkExpr)
+	result, ok := bazelCtx.cquery(label, getAllFiles)
 	if ok {
 		bazelOutput := strings.TrimSpace(result)
 		return strings.Split(bazelOutput, ", "), true
@@ -119,11 +125,13 @@
 }
 
 func NewBazelContext(c *config) (BazelContext, error) {
-	if c.Getenv("USE_BAZEL") != "1" {
+	// TODO(cparsons): Assess USE_BAZEL=1 instead once "mixed Soong/Bazel builds"
+	// are production ready.
+	if c.Getenv("USE_BAZEL_ANALYSIS") != "1" {
 		return noopBazelContext{}, nil
 	}
 
-	bazelCtx := bazelContext{requests: make(map[cqueryKey]bool)}
+	bazelCtx := bazelContext{buildDir: c.buildDir, requests: make(map[cqueryKey]bool)}
 	missingEnvVars := []string{}
 	if len(c.Getenv("BAZEL_HOME")) > 1 {
 		bazelCtx.homeDir = c.Getenv("BAZEL_HOME")
@@ -161,8 +169,8 @@
 // If the given request was already made (and the results are available), then
 // returns (result, true). If the request is queued but no results are available,
 // then returns ("", false).
-func (context *bazelContext) cquery(label string, starlarkExpr string) (string, bool) {
-	key := cqueryKey{label, starlarkExpr}
+func (context *bazelContext) cquery(label string, requestType CqueryRequestType) (string, bool) {
+	key := cqueryKey{label, requestType}
 	if result, ok := context.results[key]; ok {
 		return result, true
 	} else {
@@ -184,7 +192,8 @@
 func (context *bazelContext) issueBazelCommand(command string, labels []string,
 	extraFlags ...string) (string, error) {
 
-	cmdFlags := []string{"--output_base=" + context.outputBase, command}
+	cmdFlags := []string{"--bazelrc=build/bazel/common.bazelrc",
+		"--output_base=" + context.outputBase, command}
 	cmdFlags = append(cmdFlags, labels...)
 	cmdFlags = append(cmdFlags, extraFlags...)
 
@@ -202,27 +211,113 @@
 	}
 }
 
+func (context *bazelContext) mainBzlFileContents() []byte {
+	contents := `
+# This file is generated by soong_build. Do not edit.
+def _mixed_build_root_impl(ctx):
+    return [DefaultInfo(files = depset(ctx.files.deps))]
+
+mixed_build_root = rule(
+    implementation = _mixed_build_root_impl,
+    attrs = {"deps" : attr.label_list()},
+)
+`
+	return []byte(contents)
+}
+
+func (context *bazelContext) mainBuildFileContents() []byte {
+	formatString := `
+# This file is generated by soong_build. Do not edit.
+load(":main.bzl", "mixed_build_root")
+
+mixed_build_root(name = "buildroot",
+    deps = [%s],
+)
+`
+	var buildRootDeps []string = nil
+	for val, _ := range context.requests {
+		buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\"", val.label))
+	}
+	buildRootDepsString := strings.Join(buildRootDeps, ",\n            ")
+
+	return []byte(fmt.Sprintf(formatString, buildRootDepsString))
+}
+
+func (context *bazelContext) cqueryStarlarkFileContents() []byte {
+	formatString := `
+# This file is generated by soong_build. Do not edit.
+getAllFilesLabels = {
+  %s
+}
+
+def format(target):
+  if str(target.label) in getAllFilesLabels:
+    return str(target.label) + ">>" + ', '.join([f.path for f in target.files.to_list()])
+  else:
+    # This target was not requested via cquery, and thus must be a dependency
+    # of a requested target.
+    return ""
+`
+	var buildRootDeps []string = nil
+	// TODO(cparsons): Sort by request type instead of assuming all requests
+	// are of GetAllFiles type.
+	for val, _ := range context.requests {
+		buildRootDeps = append(buildRootDeps, fmt.Sprintf("\"%s\" : True", val.label))
+	}
+	buildRootDepsString := strings.Join(buildRootDeps, ",\n  ")
+
+	return []byte(fmt.Sprintf(formatString, buildRootDepsString))
+}
+
 // Issues commands to Bazel to receive results for all cquery requests
 // queued in the BazelContext.
 func (context *bazelContext) InvokeBazel() error {
 	context.results = make(map[cqueryKey]string)
 
-	var labels []string
 	var cqueryOutput string
 	var err error
+	err = ioutil.WriteFile(
+		absolutePath(filepath.Join(context.buildDir, "main.bzl")),
+		context.mainBzlFileContents(), 0666)
+	if err != nil {
+		return err
+	}
+	err = ioutil.WriteFile(
+		absolutePath(filepath.Join(context.buildDir, "BUILD.bazel")),
+		context.mainBuildFileContents(), 0666)
+	if err != nil {
+		return err
+	}
+	cquery_file_relpath := filepath.Join(context.buildDir, "buildroot.cquery")
+	err = ioutil.WriteFile(
+		absolutePath(cquery_file_relpath),
+		context.cqueryStarlarkFileContents(), 0666)
+	if err != nil {
+		return err
+	}
+	buildroot_label := fmt.Sprintf("//%s:buildroot", context.buildDir)
+	cqueryOutput, err = context.issueBazelCommand("cquery",
+		[]string{fmt.Sprintf("deps(%s)", buildroot_label)},
+		"--output=starlark",
+		"--starlark:file="+cquery_file_relpath)
+
+	if err != nil {
+		return err
+	}
+
+	cqueryResults := map[string]string{}
+	for _, outputLine := range strings.Split(cqueryOutput, "\n") {
+		if strings.Contains(outputLine, ">>") {
+			splitLine := strings.SplitN(outputLine, ">>", 2)
+			cqueryResults[splitLine[0]] = splitLine[1]
+		}
+	}
+
 	for val, _ := range context.requests {
-		labels = append(labels, val.label)
-
-		// TODO(cparsons): Combine requests into a batch cquery request.
-		// TODO(cparsons): Use --query_file to avoid command line limits.
-		cqueryOutput, err = context.issueBazelCommand("cquery", []string{val.label},
-			"--output=starlark",
-			"--starlark:expr="+val.starlarkExpr)
-
-		if err != nil {
-			return err
+		if cqueryResult, ok := cqueryResults[val.label]; ok {
+			context.results[val] = string(cqueryResult)
 		} else {
-			context.results[val] = string(cqueryOutput)
+			return fmt.Errorf("missing result for bazel target %s", val.label)
 		}
 	}
 
@@ -231,7 +326,7 @@
 	// bazel actions should either be added to the Ninja file and executed later,
 	// or bazel should handle execution.
 	// TODO(cparsons): Use --target_pattern_file to avoid command line limits.
-	_, err = context.issueBazelCommand("build", labels)
+	_, err = context.issueBazelCommand("build", []string{buildroot_label})
 
 	if err != nil {
 		return err
diff --git a/android/config.go b/android/config.go
index 5f1acf6..a499057 100644
--- a/android/config.go
+++ b/android/config.go
@@ -793,6 +793,11 @@
 	return Bool(c.productVariables.Always_use_prebuilt_sdks)
 }
 
+// Returns true if the boot jars check should be skipped.
+func (c *config) SkipBootJarsCheck() bool {
+	return Bool(c.productVariables.Skip_boot_jars_check)
+}
+
 func (c *config) Fuchsia() bool {
 	return Bool(c.productVariables.Fuchsia)
 }
@@ -1341,6 +1346,11 @@
 	return l.jars[idx]
 }
 
+// Apex component of idx-th pair on the list.
+func (l *ConfiguredJarList) Apex(idx int) string {
+	return l.apexes[idx]
+}
+
 // If the list contains a pair with the given jar.
 func (l *ConfiguredJarList) ContainsJar(jar string) bool {
 	return InList(jar, l.jars)
@@ -1361,14 +1371,31 @@
 	return IndexList(jar, l.jars)
 }
 
+func copyAndAppend(list []string, item string) []string {
+	// Create the result list to be 1 longer than the input.
+	result := make([]string, len(list)+1)
+
+	// Copy the whole input list into the result.
+	count := copy(result, list)
+
+	// Insert the extra item at the end.
+	result[count] = item
+
+	return result
+}
+
 // Append an (apex, jar) pair to the list.
-func (l *ConfiguredJarList) Append(apex string, jar string) {
-	l.apexes = append(l.apexes, apex)
-	l.jars = append(l.jars, jar)
+func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
+	// Create a copy of the backing arrays before appending to avoid sharing backing
+	// arrays that are mutated across instances.
+	apexes := copyAndAppend(l.apexes, apex)
+	jars := copyAndAppend(l.jars, jar)
+
+	return ConfiguredJarList{apexes, jars}
 }
 
 // Filter out sublist.
-func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) {
+func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
 	apexes := make([]string, 0, l.Len())
 	jars := make([]string, 0, l.Len())
 
@@ -1380,13 +1407,7 @@
 		}
 	}
 
-	l.apexes = apexes
-	l.jars = jars
-}
-
-// A copy of itself.
-func (l *ConfiguredJarList) CopyOf() ConfiguredJarList {
-	return ConfiguredJarList{CopyOf(l.apexes), CopyOf(l.jars)}
+	return ConfiguredJarList{apexes, jars}
 }
 
 // A copy of the list of strings containing jar components.
@@ -1469,6 +1490,14 @@
 	return paths
 }
 
+func (l *ConfiguredJarList) String() string {
+	var pairs []string
+	for i := 0; i < l.Len(); i++ {
+		pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
+	}
+	return strings.Join(pairs, ",")
+}
+
 func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
 	// Now we need to populate this list by splitting each item in the slice of
 	// pairs and appending them to the appropriate list of apexes or jars.
@@ -1497,10 +1526,10 @@
 	}
 }
 
-func CreateConfiguredJarList(ctx PathContext, list []string) ConfiguredJarList {
+func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
 	apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
 	if err != nil {
-		ReportPathErrorf(ctx, "%s", err)
+		panic(err)
 	}
 
 	return ConfiguredJarList{apexes, jars}
@@ -1519,3 +1548,11 @@
 		return list
 	}).([]string)
 }
+
+func (c *config) NonUpdatableBootJars() ConfiguredJarList {
+	return c.productVariables.BootJars
+}
+
+func (c *config) UpdatableBootJars() ConfiguredJarList {
+	return c.productVariables.UpdatableBootJars
+}
diff --git a/android/config_test.go b/android/config_test.go
index 274d59f..68f68a0 100644
--- a/android/config_test.go
+++ b/android/config_test.go
@@ -91,3 +91,49 @@
 		t.Errorf("Expected false")
 	}
 }
+
+func assertStringEquals(t *testing.T, expected, actual string) {
+	if actual != expected {
+		t.Errorf("expected %q found %q", expected, actual)
+	}
+}
+
+func TestConfiguredJarList(t *testing.T) {
+	list1 := CreateTestConfiguredJarList([]string{"apex1:jarA"})
+
+	t.Run("create", func(t *testing.T) {
+		assertStringEquals(t, "apex1:jarA", list1.String())
+	})
+
+	list2 := list1.Append("apex2", "jarB")
+	t.Run("append", func(t *testing.T) {
+		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
+	})
+
+	t.Run("append does not modify", func(t *testing.T) {
+		assertStringEquals(t, "apex1:jarA", list1.String())
+	})
+
+	// Make sure that two lists created by appending to the same list do not share storage.
+	list3 := list1.Append("apex3", "jarC")
+	t.Run("append does not share", func(t *testing.T) {
+		assertStringEquals(t, "apex1:jarA,apex2:jarB", list2.String())
+		assertStringEquals(t, "apex1:jarA,apex3:jarC", list3.String())
+	})
+
+	list4 := list3.RemoveList(list1)
+	t.Run("remove", func(t *testing.T) {
+		assertStringEquals(t, "apex3:jarC", list4.String())
+	})
+
+	t.Run("remove does not modify", func(t *testing.T) {
+		assertStringEquals(t, "apex1:jarA,apex3:jarC", list3.String())
+	})
+
+	// Make sure that two lists created by removing from the same list do not share storage.
+	list5 := list3.RemoveList(CreateTestConfiguredJarList([]string{"apex3:jarC"}))
+	t.Run("remove", func(t *testing.T) {
+		assertStringEquals(t, "apex3:jarC", list4.String())
+		assertStringEquals(t, "apex1:jarA", list5.String())
+	})
+}
diff --git a/android/variable.go b/android/variable.go
index 7999f0f..a9a9c87 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -224,6 +224,7 @@
 	Unbundled_build              *bool `json:",omitempty"`
 	Unbundled_build_apps         *bool `json:",omitempty"`
 	Always_use_prebuilt_sdks     *bool `json:",omitempty"`
+	Skip_boot_jars_check         *bool `json:",omitempty"`
 	Malloc_not_svelte            *bool `json:",omitempty"`
 	Malloc_zero_contents         *bool `json:",omitempty"`
 	Malloc_pattern_fill_contents *bool `json:",omitempty"`
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index c7223c4..3fa3a10 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -419,7 +419,10 @@
 ndk_crtend_so.21(minSdkVersion:(no version))
 ndk_crtend_so.27(minSdkVersion:(no version))
 ndk_libc++_static(minSdkVersion:(no version))
+ndk_libc++_static(minSdkVersion:16)
 ndk_libc++abi(minSdkVersion:(no version))
+ndk_libc++abi(minSdkVersion:16)
+ndk_libunwind(minSdkVersion:16)
 net-utils-framework-common(minSdkVersion:current)
 netd_aidl_interface-unstable-java(minSdkVersion:29)
 netd_event_listener_interface-ndk_platform(minSdkVersion:29)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index f400936..7e83070 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -5791,12 +5791,9 @@
 	var err string
 	var transform func(*dexpreopt.GlobalConfig)
 
-	config := android.TestArchConfig(buildDir, nil, "", nil)
-	ctx := android.PathContextForTesting(config)
-
 	t.Run("updatable jar from ART apex in the ART boot image => ok", func(t *testing.T) {
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"com.android.art.something:some-art-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, "", transform)
 	})
@@ -5804,7 +5801,7 @@
 	t.Run("updatable jar from ART apex in the framework boot image => error", func(t *testing.T) {
 		err = `module "some-art-lib" from updatable apexes \["com.android.art.something"\] is not allowed in the framework boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateConfiguredJarList(ctx, []string{"com.android.art.something:some-art-lib"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"com.android.art.something:some-art-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
@@ -5812,7 +5809,7 @@
 	t.Run("updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
 		err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the ART boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
@@ -5820,7 +5817,7 @@
 	t.Run("non-updatable jar from some other apex in the ART boot image => error", func(t *testing.T) {
 		err = `module "some-non-updatable-apex-lib" is not allowed in the ART boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
@@ -5828,14 +5825,14 @@
 	t.Run("updatable jar from some other apex in the framework boot image => error", func(t *testing.T) {
 		err = `module "some-updatable-apex-lib" from updatable apexes \["some-updatable-apex"\] is not allowed in the framework boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-updatable-apex:some-updatable-apex-lib"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"some-updatable-apex:some-updatable-apex-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("non-updatable jar from some other apex in the framework boot image => ok", func(t *testing.T) {
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateConfiguredJarList(ctx, []string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"some-non-updatable-apex:some-non-updatable-apex-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, "", transform)
 	})
@@ -5843,7 +5840,7 @@
 	t.Run("nonexistent jar in the ART boot image => error", func(t *testing.T) {
 		err = "failed to find a dex jar path for module 'nonexistent'"
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
@@ -5851,7 +5848,7 @@
 	t.Run("nonexistent jar in the framework boot image => error", func(t *testing.T) {
 		err = "failed to find a dex jar path for module 'nonexistent'"
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:nonexistent"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:nonexistent"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
@@ -5859,14 +5856,14 @@
 	t.Run("platform jar in the ART boot image => error", func(t *testing.T) {
 		err = `module "some-platform-lib" is not allowed in the ART boot image`
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.ArtApexJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
+			config.ArtApexJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, err, transform)
 	})
 
 	t.Run("platform jar in the framework boot image => ok", func(t *testing.T) {
 		transform = func(config *dexpreopt.GlobalConfig) {
-			config.BootJars = android.CreateConfiguredJarList(ctx, []string{"platform:some-platform-lib"})
+			config.BootJars = android.CreateTestConfiguredJarList([]string{"platform:some-platform-lib"})
 		}
 		testNoUpdatableJarsInBootImage(t, "", transform)
 	})
@@ -5905,7 +5902,7 @@
 	for _, apexBootJar := range apexBootJars {
 		updatableBootJars = append(updatableBootJars, "myapex:"+apexBootJar)
 	}
-	config.TestProductVariables.UpdatableBootJars = android.CreateConfiguredJarList(nil, updatableBootJars)
+	config.TestProductVariables.UpdatableBootJars = android.CreateTestConfiguredJarList(updatableBootJars)
 
 	ctx.Register(config)
 
diff --git a/bazel/bazelenv.sh b/bazel/bazelenv.sh
index 2ca8baf..fcf71f1 100755
--- a/bazel/bazelenv.sh
+++ b/bazel/bazelenv.sh
@@ -59,12 +59,16 @@
     export BAZEL_PATH="$(which bazel)"
 fi
 
-export USE_BAZEL=1
+# TODO(cparsons): Use USE_BAZEL=1 instead once "mixed Soong/Bazel builds" are
+# production ready.
+export USE_BAZEL_ANALYSIS=1
+# TODO(cparsons): Retrieve this information in either envsetup.sh or 
+# bazel.sh.
 export BAZEL_HOME="$BASE_DIR/bazelhome"
 export BAZEL_OUTPUT_BASE="$BASE_DIR/output"
 export BAZEL_WORKSPACE="$(gettop)"
 
-echo "USE_BAZEL=${USE_BAZEL}"
+echo "USE_BAZEL_ANALYSIS=${USE_BAZEL_ANALYSIS}"
 echo "BAZEL_PATH=${BAZEL_PATH}"
 echo "BAZEL_HOME=${BAZEL_HOME}"
 echo "BAZEL_OUTPUT_BASE=${BAZEL_OUTPUT_BASE}"
diff --git a/build_test.bash b/build_test.bash
index ee979e7..a53a585 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -43,5 +43,16 @@
     ;;
 esac
 
+function bazel_cleanup {
+  "${TOP}/tools/bazel" shutdown
+}
+trap bazel_cleanup EXIT
+
+echo
+echo "Running Bazel smoke test..."
+"${TOP}/tools/bazel" info
+
+echo
+echo "Running Soong test..."
 soong_build_go multiproduct_kati android/soong/cmd/multiproduct_kati
 exec "$(getoutdir)/multiproduct_kati" "$@"
diff --git a/cc/androidmk.go b/cc/androidmk.go
index 91eb886..38269cb 100644
--- a/cc/androidmk.go
+++ b/cc/androidmk.go
@@ -487,9 +487,21 @@
 	entries.ExtraEntries = append(entries.ExtraEntries, func(entries *android.AndroidMkEntries) {
 		c.libraryDecorator.androidMkWriteExportedFlags(entries)
 
+		// Specifying stem is to pass check_elf_files when vendor modules link against vndk prebuilt.
+		// We can't use install path because VNDKs are not installed. Instead, Srcs is directly used.
+		_, file := filepath.Split(c.properties.Srcs[0])
+		stem, suffix, ext := android.SplitFileExt(file)
+		entries.SetString("LOCAL_BUILT_MODULE_STEM", "$(LOCAL_MODULE)"+ext)
+		entries.SetString("LOCAL_MODULE_SUFFIX", suffix)
+		entries.SetString("LOCAL_MODULE_STEM", stem)
+
 		if c.tocFile.Valid() {
 			entries.SetString("LOCAL_SOONG_TOC", c.tocFile.String())
 		}
+
+		// VNDK libraries available to vendor are not installed because
+		// they are packaged in VNDK APEX and installed by APEX packages (apex/apex.go)
+		entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
 	})
 }
 
diff --git a/cc/cc.go b/cc/cc.go
index c93bdeb..3b01fb2 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -3085,6 +3085,12 @@
 	}
 }
 
+func squashVendorRamdiskSrcs(m *Module) {
+	if lib, ok := m.compiler.(*libraryDecorator); ok {
+		lib.baseCompiler.Properties.Exclude_srcs = append(lib.baseCompiler.Properties.Exclude_srcs, lib.baseCompiler.Properties.Target.Vendor_ramdisk.Exclude_srcs...)
+	}
+}
+
 func (c *Module) IsSdkVariant() bool {
 	return c.Properties.IsSdkVariant || c.AlwaysSdk()
 }
diff --git a/cc/compiler.go b/cc/compiler.go
index 21da2fc..e2a33d7 100644
--- a/cc/compiler.go
+++ b/cc/compiler.go
@@ -177,6 +177,15 @@
 			// build the recovery variant of the C/C++ module.
 			Exclude_generated_sources []string
 		}
+		Vendor_ramdisk struct {
+			// list of source files that should not be used to
+			// build the vendor ramdisk variant of the C/C++ module.
+			Exclude_srcs []string `android:"path"`
+
+			// List of additional cflags that should be used to build the vendor ramdisk
+			// variant of the C/C++ module.
+			Cflags []string
+		}
 	}
 
 	Proto struct {
@@ -290,6 +299,7 @@
 	CheckBadCompilerFlags(ctx, "asflags", compiler.Properties.Asflags)
 	CheckBadCompilerFlags(ctx, "vendor.cflags", compiler.Properties.Target.Vendor.Cflags)
 	CheckBadCompilerFlags(ctx, "recovery.cflags", compiler.Properties.Target.Recovery.Cflags)
+	CheckBadCompilerFlags(ctx, "vendor_ramdisk.cflags", compiler.Properties.Target.Vendor_ramdisk.Cflags)
 
 	esc := proptools.NinjaAndShellEscapeList
 
@@ -471,6 +481,10 @@
 		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Recovery.Cflags)...)
 	}
 
+	if ctx.inVendorRamdisk() {
+		flags.Local.CFlags = append(flags.Local.CFlags, esc(compiler.Properties.Target.Vendor_ramdisk.Cflags)...)
+	}
+
 	// We can enforce some rules more strictly in the code we own. strict
 	// indicates if this is code that we can be stricter with. If we have
 	// rules that we want to apply to *our* code (but maybe can't for
diff --git a/cc/image.go b/cc/image.go
index ba091e1..7b9425f 100644
--- a/cc/image.go
+++ b/cc/image.go
@@ -353,8 +353,11 @@
 
 func (c *Module) SetImageVariation(ctx android.BaseModuleContext, variant string, module android.Module) {
 	m := module.(*Module)
-	if variant == android.RamdiskVariation || variant == android.VendorRamdiskVariation {
+	if variant == android.RamdiskVariation {
 		m.MakeAsPlatform()
+	} else if variant == android.VendorRamdiskVariation {
+		m.MakeAsPlatform()
+		squashVendorRamdiskSrcs(m)
 	} else if variant == android.RecoveryVariation {
 		m.MakeAsPlatform()
 		squashRecoverySrcs(m)
diff --git a/cc/library.go b/cc/library.go
index 0e0f143..910fc31 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -833,6 +833,13 @@
 		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_shared_libs)
 		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Ramdisk.Exclude_static_libs)
 	}
+	if ctx.inVendorRamdisk() {
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, library.baseLinker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+	}
 
 	return deps
 }
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index fcf6069..fa6b326 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -383,12 +383,25 @@
 }
 
 func (p *nativeLibInfoProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+	addOutputFile := true
 	ccModule := variant.(*Module)
 
-	// If the library has some link types then it produces an output binary file, otherwise it
-	// is header only.
-	if !p.memberType.noOutputFiles {
-		p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
+	if s := ccModule.sanitize; s != nil {
+		// We currently do not capture sanitizer flags for libs with sanitizers
+		// enabled, because they may vary among variants that cannot be represented
+		// in the input blueprint files. In particular, sanitizerDepsMutator enables
+		// various sanitizers on dependencies, but in many cases only on static
+		// ones, and we cannot specify sanitizer flags at the link type level (i.e.
+		// in StaticOrSharedProperties).
+		if s.isUnsanitizedVariant() {
+			// This still captures explicitly disabled sanitizers, which may be
+			// necessary to avoid cyclic dependencies.
+			p.Sanitize = s.Properties.Sanitize
+		} else {
+			// Do not add the output file to the snapshot if we don't represent it
+			// properly.
+			addOutputFile = false
+		}
 	}
 
 	exportedInfo := ctx.SdkModuleContext().OtherModuleProvider(variant, FlagExporterInfoProvider).(FlagExporterInfo)
@@ -431,8 +444,8 @@
 		p.StubsVersions = ccModule.AllStubsVersions()
 	}
 
-	if ccModule.sanitize != nil {
-		p.Sanitize = ccModule.sanitize.Properties.Sanitize
+	if !p.memberType.noOutputFiles && addOutputFile {
+		p.outputFile = getRequiredMemberOutputFile(ctx, ccModule)
 	}
 }
 
diff --git a/cc/linker.go b/cc/linker.go
index 12c8b2c..7f13e28 100644
--- a/cc/linker.go
+++ b/cc/linker.go
@@ -158,6 +158,15 @@
 			// the ramdisk variant of the C/C++ module.
 			Exclude_static_libs []string
 		}
+		Vendor_ramdisk struct {
+			// list of shared libs that should not be used to build
+			// the recovery variant of the C/C++ module.
+			Exclude_shared_libs []string
+
+			// list of static libs that should not be used to build
+			// the vendor ramdisk variant of the C/C++ module.
+			Exclude_static_libs []string
+		}
 		Platform struct {
 			// list of shared libs that should be use to build the platform variant
 			// of a module that sets sdk_version.  This should rarely be necessary,
@@ -259,12 +268,20 @@
 	}
 
 	if ctx.inRamdisk() {
-		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Recovery.Exclude_shared_libs)
-		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Recovery.Exclude_shared_libs)
-		deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Recovery.Static_libs...)
-		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
-		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Recovery.Exclude_static_libs)
-		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Recovery.Exclude_static_libs)
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Ramdisk.Exclude_shared_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Ramdisk.Exclude_shared_libs)
+		deps.StaticLibs = append(deps.StaticLibs, linker.Properties.Target.Ramdisk.Static_libs...)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Ramdisk.Exclude_static_libs)
+	}
+
+	if ctx.inVendorRamdisk() {
+		deps.SharedLibs = removeListFromList(deps.SharedLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+		deps.ReexportSharedLibHeaders = removeListFromList(deps.ReexportSharedLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_shared_libs)
+		deps.StaticLibs = removeListFromList(deps.StaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+		deps.ReexportStaticLibHeaders = removeListFromList(deps.ReexportStaticLibHeaders, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
+		deps.WholeStaticLibs = removeListFromList(deps.WholeStaticLibs, linker.Properties.Target.Vendor_ramdisk.Exclude_static_libs)
 	}
 
 	if !ctx.useSdk() {
diff --git a/cc/vndk_prebuilt.go b/cc/vndk_prebuilt.go
index 82a7732..dddd5ac 100644
--- a/cc/vndk_prebuilt.go
+++ b/cc/vndk_prebuilt.go
@@ -232,6 +232,14 @@
 		&prebuilt.properties,
 	)
 
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) {
+		// empty BOARD_VNDK_VERSION implies that the device won't support
+		// system only OTA. In this case, VNDK snapshots aren't needed.
+		if ctx.DeviceConfig().VndkVersion() == "" {
+			ctx.Module().Disable()
+		}
+	})
+
 	return module
 }
 
diff --git a/java/Android.bp b/java/Android.bp
index 92e8ca4..9e8dc78 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -22,6 +22,7 @@
         "androidmk.go",
         "app_builder.go",
         "app.go",
+        "boot_jars.go",
         "builder.go",
         "device_host_converter.go",
         "dex.go",
diff --git a/java/androidmk.go b/java/androidmk.go
index c21c83a..e1a661f 100644
--- a/java/androidmk.go
+++ b/java/androidmk.go
@@ -217,10 +217,6 @@
 			func(entries *android.AndroidMkEntries) {
 				if prebuilt.dexJarFile != nil {
 					entries.SetPath("LOCAL_SOONG_DEX_JAR", prebuilt.dexJarFile)
-					// TODO(b/125517186): export the dex jar as a classes jar to match some mis-uses in Make until
-					// boot_jars_package_check.mk can check dex jars.
-					entries.SetPath("LOCAL_SOONG_HEADER_JAR", prebuilt.dexJarFile)
-					entries.SetPath("LOCAL_SOONG_CLASSES_JAR", prebuilt.dexJarFile)
 				}
 				if len(prebuilt.dexpreopter.builtInstalled) > 0 {
 					entries.SetString("LOCAL_SOONG_BUILT_INSTALLED", prebuilt.dexpreopter.builtInstalled)
diff --git a/java/boot_jars.go b/java/boot_jars.go
new file mode 100644
index 0000000..900eb7a
--- /dev/null
+++ b/java/boot_jars.go
@@ -0,0 +1,123 @@
+// Copyright 2020 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"android/soong/android"
+)
+
+func init() {
+	android.RegisterSingletonType("boot_jars", bootJarsSingletonFactory)
+}
+
+func bootJarsSingletonFactory() android.Singleton {
+	return &bootJarsSingleton{}
+}
+
+type bootJarsSingleton struct{}
+
+func populateMapFromConfiguredJarList(ctx android.SingletonContext, moduleToApex map[string]string, list android.ConfiguredJarList, name string) bool {
+	for i := 0; i < list.Len(); i++ {
+		module := list.Jar(i)
+		// Ignore jacocoagent it is only added when instrumenting and so has no impact on
+		// app compatibility.
+		if module == "jacocoagent" {
+			continue
+		}
+		apex := list.Apex(i)
+		if existing, ok := moduleToApex[module]; ok {
+			ctx.Errorf("Configuration property %q is invalid as it contains multiple references to module (%s) in APEXes (%s and %s)",
+				module, existing, apex)
+			return false
+		}
+
+		moduleToApex[module] = apex
+	}
+
+	return true
+}
+
+func (b *bootJarsSingleton) GenerateBuildActions(ctx android.SingletonContext) {
+	config := ctx.Config()
+	if config.SkipBootJarsCheck() {
+		return
+	}
+
+	// Populate a map from module name to APEX from the boot jars. If there is a problem
+	// such as duplicate modules then fail and return immediately.
+	moduleToApex := make(map[string]string)
+	if !populateMapFromConfiguredJarList(ctx, moduleToApex, config.NonUpdatableBootJars(), "BootJars") ||
+		!populateMapFromConfiguredJarList(ctx, moduleToApex, config.UpdatableBootJars(), "UpdatableBootJars") {
+		return
+	}
+
+	// Map from module name to the correct apex variant.
+	nameToApexVariant := make(map[string]android.Module)
+
+	// Scan all the modules looking for the module/apex variants corresponding to the
+	// boot jars.
+	ctx.VisitAllModules(func(module android.Module) {
+		name := ctx.ModuleName(module)
+		if apex, ok := moduleToApex[name]; ok {
+			apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
+			if (apex == "platform" && apexInfo.IsForPlatform()) || apexInfo.InApex(apex) {
+				// The module name/apex variant should be unique in the system but double check
+				// just in case something has gone wrong.
+				if existing, ok := nameToApexVariant[name]; ok {
+					ctx.Errorf("found multiple variants matching %s:%s: %q and %q", apex, name, existing, module)
+				}
+				nameToApexVariant[name] = module
+			}
+		}
+	})
+
+	timestamp := android.PathForOutput(ctx, "boot-jars-package-check/stamp")
+
+	rule := android.NewRuleBuilder()
+	checkBootJars := rule.Command().BuiltTool(ctx, "check_boot_jars").
+		Input(android.PathForSource(ctx, "build/soong/scripts/check_boot_jars/package_allowed_list.txt"))
+
+	// If this is not an unbundled build and missing dependencies are not allowed
+	// then all the boot jars listed must have been found.
+	strict := !config.UnbundledBuild() && !config.AllowMissingDependencies()
+
+	// Iterate over the module names on the boot classpath in order
+	for _, name := range android.SortedStringKeys(moduleToApex) {
+		if apexVariant, ok := nameToApexVariant[name]; ok {
+			if dep, ok := apexVariant.(Dependency); ok {
+				// Add the implementation jars for the module to be checked. This uses implementation
+				// and resources jar as that is what the previous make based check uses.
+				for _, jar := range dep.ImplementationAndResourcesJars() {
+					checkBootJars.Input(jar)
+				}
+			} else if _, ok := apexVariant.(*DexImport); ok {
+				// TODO(b/171479578): ignore deximport when doing package check until boot_jars.go can check dex jars.
+			} else {
+				ctx.Errorf("module %q is of type %q which is not supported as a boot jar", name, ctx.ModuleType(apexVariant))
+			}
+		} else if strict {
+			ctx.Errorf("boot jars package check failed as it could not find module %q for apex %q", name, moduleToApex[name])
+		}
+	}
+
+	checkBootJars.Text("&& touch").Output(timestamp)
+	rule.Build(pctx, ctx, "boot_jars_package_check", "check boot jar packages")
+
+	// The check-boot-jars phony target depends on the timestamp created if the check succeeds.
+	ctx.Phony("check-boot-jars", timestamp)
+
+	// The droidcore phony target depends on the check-boot-jars phony target
+	ctx.Phony("droidcore", android.PathForPhony(ctx, "check-boot-jars"))
+}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 47110c9..ab31958 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -48,7 +48,7 @@
 
 	pathCtx := android.PathContextForTesting(config)
 	dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
-	dexpreoptConfig.BootJars = android.CreateConfiguredJarList(pathCtx, []string{"platform:foo", "platform:bar", "platform:baz"})
+	dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList([]string{"platform:foo", "platform:bar", "platform:baz"})
 	dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
 
 	ctx := testContext()
diff --git a/java/dexpreopt_config.go b/java/dexpreopt_config.go
index 0f8888a..c315124 100644
--- a/java/dexpreopt_config.go
+++ b/java/dexpreopt_config.go
@@ -81,13 +81,12 @@
 		targets := dexpreoptTargets(ctx)
 		deviceDir := android.PathForOutput(ctx, ctx.Config().DeviceName())
 
-		artModules := global.ArtApexJars.CopyOf()
+		artModules := global.ArtApexJars
 		// With EMMA_INSTRUMENT_FRAMEWORK=true the Core libraries depend on jacoco.
 		if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") {
-			artModules.Append("com.android.art", "jacocoagent")
+			artModules = artModules.Append("com.android.art", "jacocoagent")
 		}
-		frameworkModules := global.BootJars.CopyOf()
-		frameworkModules.RemoveList(artModules)
+		frameworkModules := global.BootJars.RemoveList(artModules)
 
 		artSubdir := "apex/art_boot_images/javalib"
 		frameworkSubdir := "system/framework"
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index 0c223d9..7acaae7 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -25,7 +25,7 @@
 
 func testConfigWithBootJars(bp string, bootJars []string) android.Config {
 	config := testConfig(nil, bp, nil)
-	config.TestProductVariables.BootJars = android.CreateConfiguredJarList(nil, bootJars)
+	config.TestProductVariables.BootJars = android.CreateTestConfiguredJarList(bootJars)
 	return config
 }
 
diff --git a/java/java.go b/java/java.go
index 4b48a15..3167512 100644
--- a/java/java.go
+++ b/java/java.go
@@ -1187,18 +1187,6 @@
 	// javaVersion flag.
 	flags.javaVersion = getJavaVersion(ctx, String(j.properties.Java_version), sdkContext(j))
 
-	// javac flags.
-	javacFlags := j.properties.Javacflags
-	if flags.javaVersion.usesJavaModules() {
-		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
-	}
-	if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
-		// For non-host binaries, override the -g flag passed globally to remove
-		// local variable debug info to reduce disk and memory usage.
-		javacFlags = append(javacFlags, "-g:source,lines")
-	}
-	javacFlags = append(javacFlags, "-Xlint:-dep-ann")
-
 	if ctx.Config().RunErrorProne() {
 		if config.ErrorProneClasspath == nil {
 			ctx.ModuleErrorf("cannot build with Error Prone, missing external/error_prone?")
@@ -1249,24 +1237,42 @@
 		}
 	}
 
-	if j.properties.Patch_module != nil && flags.javaVersion.usesJavaModules() {
-		// Manually specify build directory in case it is not under the repo root.
-		// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
-		// just adding a symlink under the root doesn't help.)
-		patchPaths := ".:" + ctx.Config().BuildDir()
-		classPath := flags.classpath.FormJavaClassPath("")
-		if classPath != "" {
-			patchPaths += ":" + classPath
-		}
-		javacFlags = append(javacFlags, "--patch-module="+String(j.properties.Patch_module)+"="+patchPaths)
-	}
-
 	// systemModules
 	flags.systemModules = deps.systemModules
 
 	// aidl flags.
 	flags.aidlFlags, flags.aidlDeps = j.aidlFlags(ctx, deps.aidlPreprocess, deps.aidlIncludeDirs)
 
+	return flags
+}
+
+func (j *Module) collectJavacFlags(ctx android.ModuleContext, flags javaBuilderFlags) javaBuilderFlags {
+	// javac flags.
+	javacFlags := j.properties.Javacflags
+
+	if ctx.Config().MinimizeJavaDebugInfo() && !ctx.Host() {
+		// For non-host binaries, override the -g flag passed globally to remove
+		// local variable debug info to reduce disk and memory usage.
+		javacFlags = append(javacFlags, "-g:source,lines")
+	}
+	javacFlags = append(javacFlags, "-Xlint:-dep-ann")
+
+	if flags.javaVersion.usesJavaModules() {
+		javacFlags = append(javacFlags, j.properties.Openjdk9.Javacflags...)
+
+		if j.properties.Patch_module != nil {
+			// Manually specify build directory in case it is not under the repo root.
+			// (javac doesn't seem to expand into symbolc links when searching for patch-module targets, so
+			// just adding a symlink under the root doesn't help.)
+			patchPaths := ".:" + ctx.Config().BuildDir()
+			classPath := flags.classpath.FormJavaClassPath("")
+			if classPath != "" {
+				patchPaths += ":" + classPath
+			}
+			javacFlags = append(javacFlags, "--patch-module="+String(j.properties.Patch_module)+"="+patchPaths)
+		}
+	}
+
 	if len(javacFlags) > 0 {
 		// optimization.
 		ctx.Variable(pctx, "javacFlags", strings.Join(javacFlags, " "))
@@ -1297,6 +1303,8 @@
 
 	srcFiles = j.genSources(ctx, srcFiles, flags)
 
+	flags = j.collectJavacFlags(ctx, flags)
+
 	srcJars := srcFiles.FilterByExt(".srcjar")
 	srcJars = append(srcJars, deps.srcJars...)
 	if aaptSrcJar != nil {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index b5c70dc..3ad32fa 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -14,6 +14,7 @@
 		"frameworks/native/libs/binder/rust",
 		"packages/modules/Virtualization",
 		"prebuilts/rust",
+		"system/bt",
 		"system/extras/profcollectd",
 		"system/hardware/interfaces/keystore2",
 		"system/security",
diff --git a/scripts/Android.bp b/scripts/Android.bp
index 92f5c53..dd03f28 100644
--- a/scripts/Android.bp
+++ b/scripts/Android.bp
@@ -1,4 +1,20 @@
 python_binary_host {
+    name: "check_boot_jars",
+    main: "check_boot_jars/check_boot_jars.py",
+    srcs: [
+        "check_boot_jars/check_boot_jars.py",
+    ],
+    version: {
+        py2: {
+            enabled: true,
+        },
+        py3: {
+            enabled: false,
+        },
+    },
+}
+
+python_binary_host {
     name: "manifest_fixer",
     main: "manifest_fixer.py",
     srcs: [
diff --git a/scripts/check_boot_jars/check_boot_jars.py b/scripts/check_boot_jars/check_boot_jars.py
new file mode 100755
index 0000000..cf4ef27
--- /dev/null
+++ b/scripts/check_boot_jars/check_boot_jars.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+
+"""
+Check boot jars.
+
+Usage: check_boot_jars.py <package_allow_list_file> <jar1> <jar2> ...
+"""
+import logging
+import os.path
+import re
+import subprocess
+import sys
+
+
+# The compiled allow list RE.
+allow_list_re = None
+
+
+def LoadAllowList(filename):
+  """ Load and compile allow list regular expressions from filename.
+  """
+  lines = []
+  with open(filename, 'r') as f:
+    for line in f:
+      line = line.strip()
+      if not line or line.startswith('#'):
+        continue
+      lines.append(line)
+  combined_re = r'^(%s)$' % '|'.join(lines)
+  global allow_list_re
+  try:
+    allow_list_re = re.compile(combined_re)
+  except re.error:
+    logging.exception(
+        'Cannot compile package allow list regular expression: %r',
+        combined_re)
+    allow_list_re = None
+    return False
+  return True
+
+
+def CheckJar(allow_list_path, jar):
+  """Check a jar file.
+  """
+  # Get the list of files inside the jar file.
+  p = subprocess.Popen(args='jar tf %s' % jar,
+      stdout=subprocess.PIPE, shell=True)
+  stdout, _ = p.communicate()
+  if p.returncode != 0:
+    return False
+  items = stdout.split()
+  classes = 0
+  for f in items:
+    if f.endswith('.class'):
+      classes += 1
+      package_name = os.path.dirname(f)
+      package_name = package_name.replace('/', '.')
+      if not package_name or not allow_list_re.match(package_name):
+        print >> sys.stderr, ('Error: %s contains class file %s, whose package name %s is empty or'
+                              ' not in the allow list %s of packages allowed on the bootclasspath.'
+                              % (jar, f, package_name, allow_list_path))
+        return False
+  if classes == 0:
+    print >> sys.stderr, ('Error: %s does not contain any class files.' % jar)
+    return False
+  return True
+
+
+def main(argv):
+  if len(argv) < 2:
+    print __doc__
+    return 1
+  allow_list_path = argv[0]
+
+  if not LoadAllowList(allow_list_path):
+    return 1
+
+  passed = True
+  for jar in argv[1:]:
+    if not CheckJar(allow_list_path, jar):
+      passed = False
+  if not passed:
+    return 1
+
+  return 0
+
+
+if __name__ == '__main__':
+  sys.exit(main(sys.argv[1:]))
diff --git a/scripts/check_boot_jars/package_allowed_list.txt b/scripts/check_boot_jars/package_allowed_list.txt
new file mode 100644
index 0000000..18ab427
--- /dev/null
+++ b/scripts/check_boot_jars/package_allowed_list.txt
@@ -0,0 +1,248 @@
+# Boot jar package name allowed list.
+# Each line is interpreted as a regular expression.
+
+###################################################
+# core-libart.jar & core-oj.jar
+java\.awt\.font
+java\.beans
+java\.io
+java\.lang
+java\.lang\.annotation
+java\.lang\.invoke
+java\.lang\.ref
+java\.lang\.reflect
+java\.math
+java\.net
+java\.nio
+java\.nio\.file
+java\.nio\.file\.spi
+java\.nio\.file\.attribute
+java\.nio\.channels
+java\.nio\.channels\.spi
+java\.nio\.charset
+java\.nio\.charset\.spi
+java\.security
+java\.security\.acl
+java\.security\.cert
+java\.security\.interfaces
+java\.security\.spec
+java\.sql
+java\.text
+java\.text\.spi
+java\.time
+java\.time\.chrono
+java\.time\.format
+java\.time\.temporal
+java\.time\.zone
+java\.util
+java\.util\.concurrent
+java\.util\.concurrent\.atomic
+java\.util\.concurrent\.locks
+java\.util\.function
+java\.util\.jar
+java\.util\.logging
+java\.util\.prefs
+java\.util\.regex
+java\.util\.spi
+java\.util\.stream
+java\.util\.zip
+# TODO: Remove javax.annotation.processing if possible, see http://b/132338110:
+javax\.annotation\.processing
+javax\.crypto
+javax\.crypto\.interfaces
+javax\.crypto\.spec
+javax\.net
+javax\.net\.ssl
+javax\.security\.auth
+javax\.security\.auth\.callback
+javax\.security\.auth\.login
+javax\.security\.auth\.x500
+javax\.security\.cert
+javax\.sql
+javax\.xml
+javax\.xml\.datatype
+javax\.xml\.namespace
+javax\.xml\.parsers
+javax\.xml\.transform
+javax\.xml\.transform\.dom
+javax\.xml\.transform\.sax
+javax\.xml\.transform\.stream
+javax\.xml\.validation
+javax\.xml\.xpath
+jdk\.internal\.util
+jdk\.internal\.vm\.annotation
+jdk\.net
+org\.w3c\.dom
+org\.w3c\.dom\.ls
+org\.w3c\.dom\.traversal
+# OpenJdk internal implementation.
+sun\.invoke\.util
+sun\.invoke\.empty
+sun\.misc
+sun\.util.*
+sun\.text.*
+sun\.security.*
+sun\.reflect.*
+sun\.nio.*
+sun\.net.*
+com\.sun\..*
+
+# TODO: Move these internal org.apache.harmony classes to libcore.*
+org\.apache\.harmony\.crypto\.internal
+org\.apache\.harmony\.dalvik
+org\.apache\.harmony\.dalvik\.ddmc
+org\.apache\.harmony\.luni\.internal\.util
+org\.apache\.harmony\.security
+org\.apache\.harmony\.security\.asn1
+org\.apache\.harmony\.security\.fortress
+org\.apache\.harmony\.security\.pkcs10
+org\.apache\.harmony\.security\.pkcs7
+org\.apache\.harmony\.security\.pkcs8
+org\.apache\.harmony\.security\.provider\.crypto
+org\.apache\.harmony\.security\.utils
+org\.apache\.harmony\.security\.x501
+org\.apache\.harmony\.security\.x509
+org\.apache\.harmony\.security\.x509\.tsp
+org\.apache\.harmony\.xml
+org\.apache\.harmony\.xml\.dom
+org\.apache\.harmony\.xml\.parsers
+
+org\.json
+org\.xmlpull\.v1
+org\.xmlpull\.v1\.sax2
+
+# TODO:  jarjar org.kxml2.io to com.android org\.kxml2\.io
+org\.kxml2\.io
+org\.xml
+org\.xml\.sax
+org\.xml\.sax\.ext
+org\.xml\.sax\.helpers
+
+dalvik\..*
+libcore\..*
+android\..*
+com\.android\..*
+###################################################
+# android.test.base.jar
+junit\.extensions
+junit\.framework
+android\.test
+android\.test\.suitebuilder\.annotation
+
+
+###################################################
+# ext.jar
+# TODO: jarjar javax.sip to com.android
+javax\.sip
+javax\.sip\.address
+javax\.sip\.header
+javax\.sip\.message
+
+# TODO: jarjar org.apache.commons to com.android
+org\.apache\.commons\.codec
+org\.apache\.commons\.codec\.binary
+org\.apache\.commons\.codec\.language
+org\.apache\.commons\.codec\.net
+org\.apache\.commons\.logging
+org\.apache\.commons\.logging\.impl
+org\.apache\.http
+org\.apache\.http\.auth
+org\.apache\.http\.auth\.params
+org\.apache\.http\.client
+org\.apache\.http\.client\.entity
+org\.apache\.http\.client\.methods
+org\.apache\.http\.client\.params
+org\.apache\.http\.client\.protocol
+org\.apache\.http\.client\.utils
+org\.apache\.http\.conn
+org\.apache\.http\.conn\.params
+org\.apache\.http\.conn\.routing
+org\.apache\.http\.conn\.scheme
+org\.apache\.http\.conn\.ssl
+org\.apache\.http\.conn\.util
+org\.apache\.http\.cookie
+org\.apache\.http\.cookie\.params
+org\.apache\.http\.entity
+org\.apache\.http\.impl
+org\.apache\.http\.impl\.auth
+org\.apache\.http\.impl\.client
+org\.apache\.http\.impl\.client
+org\.apache\.http\.impl\.conn
+org\.apache\.http\.impl\.conn\.tsccm
+org\.apache\.http\.impl\.cookie
+org\.apache\.http\.impl\.entity
+org\.apache\.http\.impl\.io
+org\.apache\.http\.impl\.io
+org\.apache\.http\.io
+org\.apache\.http\.message
+org\.apache\.http\.params
+org\.apache\.http\.protocol
+org\.apache\.http\.util
+
+# TODO: jarjar gov.nist to com.android
+gov\.nist\.core
+gov\.nist\.core\.net
+gov\.nist\.javax\.sip
+gov\.nist\.javax\.sip\.address
+gov\.nist\.javax\.sip\.clientauthutils
+gov\.nist\.javax\.sip\.header
+gov\.nist\.javax\.sip\.header\.extensions
+gov\.nist\.javax\.sip\.header\.ims
+gov\.nist\.javax\.sip\.message
+gov\.nist\.javax\.sip\.parser
+gov\.nist\.javax\.sip\.parser\.extensions
+gov\.nist\.javax\.sip\.parser\.ims
+gov\.nist\.javax\.sip\.stack
+
+org\.ccil\.cowan\.tagsoup
+org\.ccil\.cowan\.tagsoup\.jaxp
+
+###################################################
+# framework.jar
+javax\.microedition\.khronos\.opengles
+javax\.microedition\.khronos\.egl
+
+android
+
+###################################################
+# apache-xml.jar
+org\.apache\.xml\.res
+org\.apache\.xml\.utils
+org\.apache\.xml\.utils\.res
+org\.apache\.xml\.dtm
+org\.apache\.xml\.dtm\.ref
+org\.apache\.xml\.dtm\.ref\.dom2dtm
+org\.apache\.xml\.dtm\.ref\.sax2dtm
+org\.apache\.xml\.serializer
+org\.apache\.xml\.serializer\.utils
+org\.apache\.xml\.serializer\.dom3
+org\.apache\.xpath
+org\.apache\.xpath\.operations
+org\.apache\.xpath\.domapi
+org\.apache\.xpath\.functions
+org\.apache\.xpath\.res
+org\.apache\.xpath\.axes
+org\.apache\.xpath\.objects
+org\.apache\.xpath\.patterns
+org\.apache\.xpath\.jaxp
+org\.apache\.xpath\.compiler
+org\.apache\.xalan
+org\.apache\.xalan\.res
+org\.apache\.xalan\.templates
+org\.apache\.xalan\.serialize
+org\.apache\.xalan\.extensions
+org\.apache\.xalan\.processor
+org\.apache\.xalan\.transformer
+org\.apache\.xalan\.xslt
+
+###################################################
+# Packages in the google namespace across all bootclasspath jars.
+com\.google\.android\..*
+com\.google\.vr\.platform.*
+com\.google\.i18n\.phonenumbers\..*
+com\.google\.i18n\.phonenumbers
+
+###################################################
+# Packages used for Android in Chrome OS
+org\.chromium\.arc
+org\.chromium\.arc\..*
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index c1813ec..84e4f28 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -464,7 +464,6 @@
 				arm64: {
 					export_system_include_dirs: ["arm64/include"],
 					sanitize: {
-						hwaddress: true,
 						integer_overflow: false,
 					},
 				},
@@ -496,7 +495,6 @@
             srcs: ["arm64/lib/mynativelib.so"],
             export_system_include_dirs: ["arm64/include/arm64/include"],
             sanitize: {
-                hwaddress: true,
                 integer_overflow: false,
             },
         },
@@ -527,7 +525,6 @@
             srcs: ["arm64/lib/mynativelib.so"],
             export_system_include_dirs: ["arm64/include/arm64/include"],
             sanitize: {
-                hwaddress: true,
                 integer_overflow: false,
             },
         },
@@ -548,7 +545,7 @@
 `),
 		checkAllCopyRules(`
 include/Test.h -> include/include/Test.h
-.intermediates/mynativelib/android_arm64_armv8-a_shared_hwasan/mynativelib.so -> arm64/lib/mynativelib.so
+.intermediates/mynativelib/android_arm64_armv8-a_shared/mynativelib.so -> arm64/lib/mynativelib.so
 arm64/include/Arm64Test.h -> arm64/include/arm64/include/Arm64Test.h
 .intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
 	)
@@ -2727,3 +2724,75 @@
 `),
 	)
 }
+
+func TestNoSanitizerMembers(t *testing.T) {
+	result := testSdkWithCc(t, `
+		sdk {
+			name: "mysdk",
+			native_shared_libs: ["mynativelib"],
+		}
+
+		cc_library_shared {
+			name: "mynativelib",
+			srcs: ["Test.cpp"],
+			export_include_dirs: ["include"],
+			arch: {
+				arm64: {
+					export_system_include_dirs: ["arm64/include"],
+					sanitize: {
+						hwaddress: true,
+					},
+				},
+			},
+		}
+	`)
+
+	result.CheckSnapshot("mysdk", "",
+		checkAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+cc_prebuilt_library_shared {
+    name: "mysdk_mynativelib@current",
+    sdk_member_name: "mynativelib",
+    visibility: ["//visibility:public"],
+    installable: false,
+    compile_multilib: "both",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            export_system_include_dirs: ["arm64/include/arm64/include"],
+        },
+        arm: {
+            srcs: ["arm/lib/mynativelib.so"],
+        },
+    },
+}
+
+cc_prebuilt_library_shared {
+    name: "mynativelib",
+    prefer: false,
+    visibility: ["//visibility:public"],
+    compile_multilib: "both",
+    export_include_dirs: ["include/include"],
+    arch: {
+        arm64: {
+            export_system_include_dirs: ["arm64/include/arm64/include"],
+        },
+        arm: {
+            srcs: ["arm/lib/mynativelib.so"],
+        },
+    },
+}
+
+sdk_snapshot {
+    name: "mysdk@current",
+    visibility: ["//visibility:public"],
+    native_shared_libs: ["mysdk_mynativelib@current"],
+}
+`),
+		checkAllCopyRules(`
+include/Test.h -> include/include/Test.h
+arm64/include/Arm64Test.h -> arm64/include/arm64/include/Arm64Test.h
+.intermediates/mynativelib/android_arm_armv7-a-neon_shared/mynativelib.so -> arm/lib/mynativelib.so`),
+	)
+}