Merge "bp2build supports arch variant srcs for java_library"
diff --git a/android/api_levels.go b/android/api_levels.go
index 926d297..de56625 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -321,6 +321,7 @@
 			"Q":     29,
 			"R":     30,
 			"S":     31,
+			"S-V2":  32,
 		}
 
 		// TODO: Differentiate "current" and "future".
@@ -364,6 +365,7 @@
 			"Q":     29,
 			"R":     30,
 			"S":     31,
+			"S-V2":  32,
 		}
 		for i, codename := range config.PlatformVersionActiveCodenames() {
 			apiLevelsMap[codename] = previewAPILevelBase + i
diff --git a/android/arch.go b/android/arch.go
index 8aa8d40..6b81022 100644
--- a/android/arch.go
+++ b/android/arch.go
@@ -909,6 +909,7 @@
 			"Glibc",
 			"Musl",
 			"Linux",
+			"Host_linux",
 			"Not_windows",
 			"Arm_on_x86",
 			"Arm_on_x86_64",
@@ -930,6 +931,12 @@
 						targets = append(targets, target)
 					}
 				}
+				if os.Linux() && os.Class == Host {
+					target := "Host_linux_" + archType.Name
+					if !InList(target, targets) {
+						targets = append(targets, target)
+					}
+				}
 				if os.Bionic() {
 					target := "Bionic_" + archType.Name
 					if !InList(target, targets) {
@@ -1162,6 +1169,14 @@
 				}
 			}
 
+			if os.Linux() && os.Class == Host {
+				field := "Host_linux"
+				prefix := "target.host_linux"
+				if linuxProperties, ok := getChildPropertyStruct(ctx, targetProp, field, prefix); ok {
+					mergePropertyStruct(ctx, genProps, linuxProperties)
+				}
+			}
+
 			if os.Bionic() {
 				field := "Bionic"
 				prefix := "target.bionic"
@@ -2127,6 +2142,7 @@
 	linuxStructs := getTargetStructs(ctx, archProperties, "Linux")
 	bionicStructs := getTargetStructs(ctx, archProperties, "Bionic")
 	hostStructs := getTargetStructs(ctx, archProperties, "Host")
+	hostLinuxStructs := getTargetStructs(ctx, archProperties, "Host_linux")
 	hostNotWindowsStructs := getTargetStructs(ctx, archProperties, "Not_windows")
 
 	// For android, linux, ...
@@ -2147,6 +2163,9 @@
 		if os.Bionic() {
 			osStructs = append(osStructs, bionicStructs...)
 		}
+		if os.Linux() && os.Class == Host {
+			osStructs = append(osStructs, hostLinuxStructs...)
+		}
 
 		if os == LinuxMusl {
 			osStructs = append(osStructs, getTargetStructs(ctx, archProperties, "Musl")...)
@@ -2179,6 +2198,16 @@
 				targetStructs := getTargetStructs(ctx, archProperties, targetField)
 				osArchStructs = append(osArchStructs, targetStructs...)
 			}
+			if os == LinuxMusl {
+				targetField := "Musl_" + arch.Name
+				targetStructs := getTargetStructs(ctx, archProperties, targetField)
+				osArchStructs = append(osArchStructs, targetStructs...)
+			}
+			if os == Linux {
+				targetField := "Glibc_" + arch.Name
+				targetStructs := getTargetStructs(ctx, archProperties, targetField)
+				osArchStructs = append(osArchStructs, targetStructs...)
+			}
 
 			targetField := GetCompoundTargetField(os, arch)
 			targetName := fmt.Sprintf("%s_%s", os.Name, arch.Name)
diff --git a/android/arch_test.go b/android/arch_test.go
index 7caf837..68dc7f5 100644
--- a/android/arch_test.go
+++ b/android/arch_test.go
@@ -510,6 +510,7 @@
 				musl: { a:  ["musl"] },
 				linux_bionic: { a:  ["linux_bionic"] },
 				linux: { a:  ["linux"] },
+				host_linux: { a: ["host_linux"] },
 				linux_glibc: { a:  ["linux_glibc"] },
 				linux_musl: { a:  ["linux_musl"] },
 				windows: { a:  ["windows"], enabled: true },
@@ -566,12 +567,12 @@
 				{
 					module:   "foo",
 					variant:  "linux_glibc_x86_64",
-					property: []string{"root", "host", "linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"},
+					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_glibc_x86_64"},
 				},
 				{
 					module:   "foo",
 					variant:  "linux_glibc_x86",
-					property: []string{"root", "host", "linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"},
+					property: []string{"root", "host", "linux", "host_linux", "glibc", "linux_glibc", "not_windows", "x86", "lib32", "linux_x86", "linux_glibc_x86"},
 				},
 			},
 		},
@@ -605,12 +606,12 @@
 				{
 					module:   "foo",
 					variant:  "linux_musl_x86_64",
-					property: []string{"root", "host", "linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64", "linux_glibc_x86_64"},
+					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86_64", "lib64", "linux_x86_64", "linux_musl_x86_64", "linux_glibc_x86_64"},
 				},
 				{
 					module:   "foo",
 					variant:  "linux_musl_x86",
-					property: []string{"root", "host", "linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86", "linux_glibc_x86"},
+					property: []string{"root", "host", "linux", "host_linux", "musl", "linux_glibc", "linux_musl", "not_windows", "x86", "lib32", "linux_x86", "linux_musl_x86", "linux_glibc_x86"},
 				},
 			},
 		},
diff --git a/android/bazel.go b/android/bazel.go
index a923eb2..97226c6 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -293,6 +293,7 @@
 		"development/samples/WiFiDirectDemo":                 Bp2BuildDefaultTrue,
 		"development/sdk":                                    Bp2BuildDefaultTrueRecursively,
 		"external/arm-optimized-routines":                    Bp2BuildDefaultTrueRecursively,
+		"external/auto/android-annotation-stubs":             Bp2BuildDefaultTrueRecursively,
 		"external/auto/common":                               Bp2BuildDefaultTrueRecursively,
 		"external/auto/service":                              Bp2BuildDefaultTrueRecursively,
 		"external/boringssl":                                 Bp2BuildDefaultTrueRecursively,
diff --git a/android/config.go b/android/config.go
index 3d8bc31..e8ca84c 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1256,6 +1256,10 @@
 	return Bool(c.config.productVariables.ClangCoverage)
 }
 
+func (c *deviceConfig) ClangCoverageContinuousMode() bool {
+	return Bool(c.config.productVariables.ClangCoverageContinuousMode)
+}
+
 func (c *deviceConfig) GcovCoverageEnabled() bool {
 	return Bool(c.config.productVariables.GcovCoverage)
 }
diff --git a/android/hooks.go b/android/hooks.go
index bded764..5e3a4a7 100644
--- a/android/hooks.go
+++ b/android/hooks.go
@@ -15,7 +15,10 @@
 package android
 
 import (
+	"fmt"
+	"path"
 	"reflect"
+	"runtime"
 
 	"github.com/google/blueprint"
 	"github.com/google/blueprint/proptools"
@@ -88,7 +91,19 @@
 
 func (l *loadHookContext) CreateModule(factory ModuleFactory, props ...interface{}) Module {
 	inherited := []interface{}{&l.Module().base().commonProperties}
-	module := l.bp.CreateModule(ModuleFactoryAdaptor(factory), append(inherited, props...)...).(Module)
+
+	var typeName string
+	if typeNameLookup, ok := ModuleTypeByFactory()[reflect.ValueOf(factory)]; ok {
+		typeName = typeNameLookup
+	} else {
+		factoryPtr := reflect.ValueOf(factory).Pointer()
+		factoryFunc := runtime.FuncForPC(factoryPtr)
+		filePath, _ := factoryFunc.FileLine(factoryPtr)
+		typeName = fmt.Sprintf("%s_%s", path.Base(filePath), factoryFunc.Name())
+	}
+	typeName = typeName + "_loadHookModule"
+
+	module := l.bp.CreateModule(ModuleFactoryAdaptor(factory), typeName, append(inherited, props...)...).(Module)
 
 	if l.Module().base().variableProperties != nil && module.base().variableProperties != nil {
 		src := l.Module().base().variableProperties
diff --git a/android/register.go b/android/register.go
index 10e14e0..c505833 100644
--- a/android/register.go
+++ b/android/register.go
@@ -59,6 +59,7 @@
 
 var moduleTypes []moduleType
 var moduleTypesForDocs = map[string]reflect.Value{}
+var moduleTypeByFactory = map[reflect.Value]string{}
 
 type singleton struct {
 	// True if this should be registered as a pre-singleton, false otherwise.
@@ -140,6 +141,7 @@
 // RegisterModuleType was a lambda.
 func RegisterModuleTypeForDocs(name string, factory reflect.Value) {
 	moduleTypesForDocs[name] = factory
+	moduleTypeByFactory[factory] = name
 }
 
 func RegisterSingletonType(name string, factory SingletonFactory) {
@@ -228,6 +230,10 @@
 	return moduleTypesForDocs
 }
 
+func ModuleTypeByFactory() map[reflect.Value]string {
+	return moduleTypeByFactory
+}
+
 // Interface for registering build components.
 //
 // Provided to allow registration of build components to be shared between the runtime
diff --git a/android/variable.go b/android/variable.go
index 68f19b9..37037eb 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -306,10 +306,11 @@
 	JavaCoveragePaths        []string `json:",omitempty"`
 	JavaCoverageExcludePaths []string `json:",omitempty"`
 
-	GcovCoverage               *bool    `json:",omitempty"`
-	ClangCoverage              *bool    `json:",omitempty"`
-	NativeCoveragePaths        []string `json:",omitempty"`
-	NativeCoverageExcludePaths []string `json:",omitempty"`
+	GcovCoverage                *bool    `json:",omitempty"`
+	ClangCoverage               *bool    `json:",omitempty"`
+	NativeCoveragePaths         []string `json:",omitempty"`
+	NativeCoverageExcludePaths  []string `json:",omitempty"`
+	ClangCoverageContinuousMode *bool    `json:",omitempty"`
 
 	// Set by NewConfig
 	Native_coverage *bool `json:",omitempty"`
diff --git a/androidmk/androidmk/android.go b/androidmk/androidmk/android.go
index 295b0e5..954f8d0 100644
--- a/androidmk/androidmk/android.go
+++ b/androidmk/androidmk/android.go
@@ -17,6 +17,7 @@
 import (
 	"fmt"
 	"sort"
+	"strconv"
 	"strings"
 
 	mkparser "android/soong/androidmk/parser"
@@ -623,6 +624,16 @@
 	return err
 }
 
+// Assigns a given boolean value to a given variable in the result bp file. See
+// setVariable documentation for more information about prefix and name.
+func makeBlueprintBoolAssignment(ctx variableAssignmentContext, prefix, name string, value bool) error {
+	expressionValue, err := stringToBoolValue(strconv.FormatBool(value))
+	if err == nil {
+		err = setVariable(ctx.file, false, prefix, name, expressionValue, true)
+	}
+	return err
+}
+
 // If variable is a literal variable name, return the name, otherwise return ""
 func varLiteralName(variable mkparser.Variable) string {
 	if len(variable.Name.Variables) == 0 {
@@ -647,7 +658,11 @@
 	varname := ""
 	fixed := ""
 	val := ctx.mkvalue
+
 	if len(val.Variables) == 1 && varLiteralName(val.Variables[0]) != "" && len(val.Strings) == 2 && val.Strings[0] == "" {
+		if varLiteralName(val.Variables[0]) == "PRODUCT_OUT" && val.Strings[1] == "/system/priv-app" {
+			return makeBlueprintBoolAssignment(ctx, "", "privileged", true)
+		}
 		fixed = val.Strings[1]
 		varname = val.Variables[0].Name.Strings[0]
 		// TARGET_OUT_OPTIONAL_EXECUTABLES puts the artifact in xbin, which is
diff --git a/androidmk/androidmk/androidmk.go b/androidmk/androidmk/androidmk.go
index b8316a3..aaafdc7 100644
--- a/androidmk/androidmk/androidmk.go
+++ b/androidmk/androidmk/androidmk.go
@@ -411,6 +411,24 @@
 	return exp, nil
 }
 
+// If local is set to true, then the variable will be added as a part of the
+// variable at file.bpPos. For example, if file.bpPos references a module,
+// then calling this method will set a property on that module if local is set
+// to true. Otherwise, the Variable will be created at the root of the file.
+//
+// prefix should be populated with the top level value to be assigned, and
+// name with a sub-value. If prefix is empty, then name is the top level value.
+// For example, if prefix is "foo" and name is "bar" with a value of "baz", then
+// the following variable will be generated:
+//
+// foo {
+//   bar: "baz"
+// }
+//
+// If prefix is the empty string and name is "foo" with a value of "bar", the
+// following variable will be generated (if it is a property):
+//
+// foo: "bar"
 func setVariable(file *bpFile, plusequals bool, prefix, name string, value bpparser.Expression, local bool) error {
 	if prefix != "" {
 		name = prefix + "." + name
diff --git a/androidmk/androidmk/androidmk_test.go b/androidmk/androidmk/androidmk_test.go
index e8b6f78..2176361 100644
--- a/androidmk/androidmk/androidmk_test.go
+++ b/androidmk/androidmk/androidmk_test.go
@@ -1675,6 +1675,21 @@
 }
 `,
 	},
+	{
+		desc: "privileged app",
+		in: `
+include $(CLEAR_VARS)
+LOCAL_MODULE := foo
+LOCAL_MODULE_PATH := $(PRODUCT_OUT)/system/priv-app
+include $(BUILD_PACKAGE)
+		`,
+		expected: `
+android_app {
+	name: "foo",
+	privileged: true
+}
+`,
+	},
 }
 
 func TestEndToEnd(t *testing.T) {
diff --git a/androidmk/parser/make_strings.go b/androidmk/parser/make_strings.go
index aac4c4e..8030326 100644
--- a/androidmk/parser/make_strings.go
+++ b/androidmk/parser/make_strings.go
@@ -24,14 +24,24 @@
 // A MakeString is a string that may contain variable substitutions in it.
 // It can be considered as an alternating list of raw Strings and variable
 // substitutions, where the first and last entries in the list must be raw
-// Strings (possibly empty).  A MakeString that starts with a variable
-// will have an empty first raw string, and a MakeString that ends with a
-// variable will have an empty last raw string.  Two sequential Variables
-// will have an empty raw string between them.
+// Strings (possibly empty). The entirety of the text before the first variable,
+// between two variables, and after the last variable will be considered a
+// single String value. A MakeString that starts with a variable will have an
+// empty first raw string, and a MakeString that ends with a  variable will have
+// an empty last raw string.  Two sequential Variables will have an empty raw
+// string between them.
 //
 // The MakeString is stored as two lists, a list of raw Strings and a list
 // of Variables.  The raw string list is always one longer than the variable
 // list.
+//
+// For example, "$(FOO)/bar/baz" will be represented as the
+// following lists:
+//
+// {
+//   Strings: ["", "/bar/baz"],
+//   Variables: ["FOO"]
+// }
 type MakeString struct {
 	StringPos Pos
 	Strings   []string
diff --git a/apex/androidmk.go b/apex/androidmk.go
index 8785ca0..059b4d7 100644
--- a/apex/androidmk.go
+++ b/apex/androidmk.go
@@ -373,8 +373,10 @@
 				}
 				fmt.Fprintln(w, "LOCAL_MODULE_STEM :=", name+stemSuffix)
 				fmt.Fprintln(w, "LOCAL_UNINSTALLABLE_MODULE :=", !a.installable())
-				fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
-				fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
+				if a.installable() {
+					fmt.Fprintln(w, "LOCAL_SOONG_INSTALLED_MODULE :=", a.installedFile.String())
+					fmt.Fprintln(w, "LOCAL_SOONG_INSTALL_PAIRS :=", a.outputFile.String()+":"+a.installedFile.String())
+				}
 
 				// Because apex writes .mk with Custom(), we need to write manually some common properties
 				// which are available via data.Entries
diff --git a/apex/apex.go b/apex/apex.go
index 9031a4e..ac67fee 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -1415,7 +1415,7 @@
 		for _, target := range ctx.MultiTargets() {
 			if target.Arch.ArchType.Multilib == "lib64" {
 				addDependenciesForNativeModules(ctx, ApexNativeDependencies{
-					Native_shared_libs: []string{"libclang_rt.hwasan-aarch64-android"},
+					Native_shared_libs: []string{"libclang_rt.hwasan"},
 					Tests:              nil,
 					Jni_libs:           nil,
 					Binaries:           nil,
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 1c36c75..4f2a583 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -1415,13 +1415,14 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "libclang_rt.hwasan-aarch64-android",
+			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
 			stubs: { versions: ["1"] },
+			stem: "libclang_rt.hwasan-aarch64-android",
 
 			sanitize: {
 				never: true,
@@ -1434,7 +1435,7 @@
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
 
-	hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+	hwasan := ctx.ModuleForTests("libclang_rt.hwasan", "android_arm64_armv8-a_shared")
 
 	installed := hwasan.Description("install libclang_rt.hwasan")
 	ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
@@ -1462,13 +1463,14 @@
 		}
 
 		cc_prebuilt_library_shared {
-			name: "libclang_rt.hwasan-aarch64-android",
+			name: "libclang_rt.hwasan",
 			no_libcrt: true,
 			nocrt: true,
 			stl: "none",
 			system_shared_libs: [],
 			srcs: [""],
 			stubs: { versions: ["1"] },
+			stem: "libclang_rt.hwasan-aarch64-android",
 
 			sanitize: {
 				never: true,
@@ -1482,7 +1484,7 @@
 		"lib64/bionic/libclang_rt.hwasan-aarch64-android.so",
 	})
 
-	hwasan := ctx.ModuleForTests("libclang_rt.hwasan-aarch64-android", "android_arm64_armv8-a_shared")
+	hwasan := ctx.ModuleForTests("libclang_rt.hwasan", "android_arm64_armv8-a_shared")
 
 	installed := hwasan.Description("install libclang_rt.hwasan")
 	ensureContains(t, installed.Output.String(), "/system/lib64/bootstrap/libclang_rt.hwasan-aarch64-android.so")
diff --git a/apex/builder.go b/apex/builder.go
index 183c215..8c5f99b 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -856,6 +856,10 @@
 		installSuffix = imageCapexSuffix
 	}
 
+	if !a.installable() {
+		a.SkipInstall()
+	}
+
 	// Install to $OUT/soong/{target,host}/.../apex.
 	a.installedFile = ctx.InstallFile(a.installDir, a.Name()+installSuffix, a.outputFile,
 		a.compatSymlinks.Paths()...)
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index b904c35..8a171d4 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -44,9 +44,16 @@
         "cc_library_shared_conversion_test.go",
         "cc_library_static_conversion_test.go",
         "cc_object_conversion_test.go",
+        "cc_prebuilt_library_shared_test.go",
         "conversion_test.go",
         "filegroup_conversion_test.go",
         "genrule_conversion_test.go",
+        "java_binary_host_conversion_test.go",
+        "java_import_conversion_test.go",
+        "java_library_conversion_test.go",
+        "java_library_host_conversion_test.go",
+        "java_plugin_conversion_test.go",
+        "java_proto_conversion_test.go",
         "performance_test.go",
         "prebuilt_etc_conversion_test.go",
         "python_binary_conversion_test.go",
diff --git a/bp2build/java_proto_conversion_test.go b/bp2build/java_proto_conversion_test.go
index 93b0677..61a398c 100644
--- a/bp2build/java_proto_conversion_test.go
+++ b/bp2build/java_proto_conversion_test.go
@@ -71,8 +71,7 @@
 }`
 
 	protoLibrary := makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
-		"srcs":                `["a.proto"]`,
-		"strip_import_prefix": `""`,
+		"srcs": `["a.proto"]`,
 	})
 
 	for _, tc := range testCases {
@@ -107,8 +106,7 @@
 `,
 		expectedBazelTargets: []string{
 			makeBazelTarget("proto_library", "java-protos_proto", attrNameToString{
-				"srcs":                `["a.proto"]`,
-				"strip_import_prefix": `""`,
+				"srcs": `["a.proto"]`,
 			}),
 			makeBazelTarget(
 				"java_lite_proto_library",
diff --git a/cc/binary.go b/cc/binary.go
index 0fe4490..9262f21 100644
--- a/cc/binary.go
+++ b/cc/binary.go
@@ -220,18 +220,18 @@
 func (binary *binaryDecorator) linkerInit(ctx BaseModuleContext) {
 	binary.baseLinker.linkerInit(ctx)
 
-	if !ctx.toolchain().Bionic() && !ctx.toolchain().Musl() {
-		if ctx.Os() == android.Linux {
-			// Unless explicitly specified otherwise, host static binaries are built with -static
-			// if HostStaticBinaries is true for the product configuration.
-			if binary.Properties.Static_executable == nil && ctx.Config().HostStaticBinaries() {
-				binary.Properties.Static_executable = BoolPtr(true)
-			}
-		} else {
-			// Static executables are not supported on Darwin or Windows
-			binary.Properties.Static_executable = nil
+	if ctx.Os().Linux() && ctx.Host() {
+		// Unless explicitly specified otherwise, host static binaries are built with -static
+		// if HostStaticBinaries is true for the product configuration.
+		if binary.Properties.Static_executable == nil && ctx.Config().HostStaticBinaries() {
+			binary.Properties.Static_executable = BoolPtr(true)
 		}
 	}
+
+	if ctx.Darwin() || ctx.Windows() {
+		// Static executables are not supported on Darwin or Windows
+		binary.Properties.Static_executable = nil
+	}
 }
 
 func (binary *binaryDecorator) static() bool {
diff --git a/cc/cc.go b/cc/cc.go
index a8adb0c..58ab28c 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1383,7 +1383,7 @@
 }
 
 func InstallToBootstrap(name string, config android.Config) bool {
-	if name == "libclang_rt.hwasan-aarch64-android" {
+	if name == "libclang_rt.hwasan" {
 		return true
 	}
 	return isBionic(name)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 51a6a27..278efa1 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -2944,13 +2944,13 @@
 	// Check the shared version of lib2.
 	variant := "android_arm64_armv8-a_shared"
 	module := ctx.ModuleForTests("lib2", variant).Module().(*Module)
-	checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
+	checkStaticLibs(t, []string{"lib1", "libc++demangle", "libclang_rt.builtins"}, module)
 
 	// Check the static version of lib2.
 	variant = "android_arm64_armv8-a_static"
 	module = ctx.ModuleForTests("lib2", variant).Module().(*Module)
 	// libc++_static is linked additionally.
-	checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins-aarch64-android"}, module)
+	checkStaticLibs(t, []string{"lib1", "libc++_static", "libc++demangle", "libclang_rt.builtins"}, module)
 }
 
 var compilerFlagsTestCases = []struct {
diff --git a/cc/config/toolchain.go b/cc/config/toolchain.go
index 6cede11..7175fdc 100644
--- a/cc/config/toolchain.go
+++ b/cc/config/toolchain.go
@@ -227,14 +227,7 @@
 }
 
 func LibclangRuntimeLibrary(t Toolchain, library string) string {
-	arch := t.LibclangRuntimeLibraryArch()
-	if arch == "" {
-		return ""
-	}
-	if !t.Bionic() {
-		return "libclang_rt." + library + "-" + arch
-	}
-	return "libclang_rt." + library + "-" + arch + "-android"
+	return "libclang_rt." + library
 }
 
 func BuiltinsRuntimeLibrary(t Toolchain) string {
diff --git a/cc/coverage.go b/cc/coverage.go
index f2b5425..d0902ea 100644
--- a/cc/coverage.go
+++ b/cc/coverage.go
@@ -77,6 +77,10 @@
 	return deps
 }
 
+func EnableContinuousCoverage(ctx android.BaseModuleContext) bool {
+	return ctx.DeviceConfig().ClangCoverageContinuousMode()
+}
+
 func (cov *coverage) flags(ctx ModuleContext, flags Flags, deps PathDeps) (Flags, PathDeps) {
 	clangCoverage := ctx.DeviceConfig().ClangCoverageEnabled()
 	gcovCoverage := ctx.DeviceConfig().GcovCoverageEnabled()
@@ -101,6 +105,9 @@
 			// Override -Wframe-larger-than.  We can expect frame size increase after
 			// coverage instrumentation.
 			flags.Local.CFlags = append(flags.Local.CFlags, "-Wno-frame-larger-than=")
+			if EnableContinuousCoverage(ctx) {
+				flags.Local.CommonFlags = append(flags.Local.CommonFlags, "-mllvm", "-runtime-counter-relocation")
+			}
 		}
 	}
 
@@ -152,6 +159,9 @@
 			flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,--wrap,getenv")
 		} else if clangCoverage {
 			flags.Local.LdFlags = append(flags.Local.LdFlags, profileInstrFlag)
+			if EnableContinuousCoverage(ctx) {
+				flags.Local.LdFlags = append(flags.Local.LdFlags, "-Wl,-mllvm=-runtime-counter-relocation")
+			}
 
 			coverage := ctx.GetDirectDepWithTag(getClangProfileLibraryName(ctx), CoverageDepTag).(*Module)
 			deps.WholeStaticLibs = append(deps.WholeStaticLibs, coverage.OutputFile().Path())
diff --git a/cc/sanitize_test.go b/cc/sanitize_test.go
index 0070e40..c1ca034 100644
--- a/cc/sanitize_test.go
+++ b/cc/sanitize_test.go
@@ -24,11 +24,7 @@
 
 var prepareForAsanTest = android.FixtureAddFile("asan/Android.bp", []byte(`
 	cc_library_shared {
-		name: "libclang_rt.asan-aarch64-android",
-	}
-
-	cc_library_shared {
-		name: "libclang_rt.asan-arm-android",
+		name: "libclang_rt.asan",
 	}
 `))
 
diff --git a/cc/testing.go b/cc/testing.go
index a03d147..32f7c60 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -86,54 +86,20 @@
 		}
 
 		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-arm-android",
-			defaults: ["toolchain_libs_defaults"],
-			native_bridge_supported: true,
-			vendor_ramdisk_available: true,
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-aarch64-android",
-			defaults: ["toolchain_libs_defaults"],
-			native_bridge_supported: true,
-			vendor_ramdisk_available: true,
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-x86_64",
+			name: "libclang_rt.builtins",
 			defaults: ["toolchain_libs_defaults"],
 			host_supported: true,
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-i386",
-			defaults: ["toolchain_libs_defaults"],
-			host_supported: true,
+	        vendor_available: true,
+			vendor_ramdisk_available: true,
+			native_bridge_supported: true,
 		}
 
 		cc_prebuilt_library_shared {
-			name: "libclang_rt.hwasan-aarch64-android",
+			name: "libclang_rt.hwasan",
 			defaults: ["toolchain_libs_defaults"],
 		}
 
 		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-i686-android",
-			defaults: ["toolchain_libs_defaults"],
-			vendor_ramdisk_available: true,
-			native_bridge_supported: true,
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.builtins-x86_64-android",
-			defaults: [
-				"linux_bionic_supported",
-				"toolchain_libs_defaults",
-			],
-			native_bridge_supported: true,
-			vendor_ramdisk_available: true,
-		}
-
-		cc_prebuilt_library_static {
 			name: "libunwind",
 			defaults: [
 				"linux_bionic_supported",
@@ -144,30 +110,7 @@
 		}
 
 		cc_prebuilt_library_static {
-			name: "libclang_rt.fuzzer-arm-android",
-			defaults: ["toolchain_libs_defaults"],
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.fuzzer-aarch64-android",
-			defaults: ["toolchain_libs_defaults"],
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.fuzzer-i686-android",
-			defaults: ["toolchain_libs_defaults"],
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.fuzzer-x86_64-android",
-			defaults: [
-				"linux_bionic_supported",
-				"toolchain_libs_defaults",
-			],
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.fuzzer-x86_64",
+			name: "libclang_rt.fuzzer",
 			defaults: [
 				"linux_bionic_supported",
 				"toolchain_libs_defaults",
@@ -176,17 +119,12 @@
 
 		// Needed for sanitizer
 		cc_prebuilt_library_shared {
-			name: "libclang_rt.ubsan_standalone-aarch64-android",
+			name: "libclang_rt.ubsan_standalone",
 			defaults: ["toolchain_libs_defaults"],
 		}
 
 		cc_prebuilt_library_static {
-			name: "libclang_rt.ubsan_minimal-aarch64-android",
-			defaults: ["toolchain_libs_defaults"],
-		}
-
-		cc_prebuilt_library_static {
-			name: "libclang_rt.ubsan_minimal-arm-android",
+			name: "libclang_rt.ubsan_minimal",
 			defaults: ["toolchain_libs_defaults"],
 		}
 
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 8a17e2e..e7c05ac 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -146,6 +146,7 @@
 	// binary flags
 	Symlinks         []string `json:",omitempty"`
 	StaticExecutable bool     `json:",omitempty"`
+	InstallInRoot    bool     `json:",omitempty"`
 
 	// dependencies
 	SharedLibs  []string `json:",omitempty"`
@@ -320,6 +321,7 @@
 			// binary flags
 			prop.Symlinks = m.Symlinks()
 			prop.StaticExecutable = m.StaticExecutable()
+			prop.InstallInRoot = m.InstallInRoot()
 			prop.SharedLibs = m.SnapshotSharedLibs()
 			// static libs dependencies are required to collect the NOTICE files.
 			prop.StaticLibs = m.SnapshotStaticLibs()
diff --git a/cc/vndk.go b/cc/vndk.go
index c9c9f2c..bf6148b 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -450,7 +450,7 @@
 // Therefore, by removing the library here, we cause it to only be installed if libc
 // depends on it.
 func llndkLibrariesTxtFactory() android.SingletonModule {
-	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan-")
+	return newVndkLibrariesWithMakeVarFilter(llndkLibraries, "LLNDK_LIBRARIES", "libclang_rt.hwasan")
 }
 
 // vndksp_libraries_txt is a singleton module whose content is a list of VNDKSP libraries
diff --git a/dexpreopt/DEXPREOPT_IMPLEMENTATION.md b/dexpreopt/DEXPREOPT_IMPLEMENTATION.md
new file mode 100644
index 0000000..c3a1730
--- /dev/null
+++ b/dexpreopt/DEXPREOPT_IMPLEMENTATION.md
@@ -0,0 +1,258 @@
+## Dexpreopt implementation
+
+### Introduction
+
+All dexpreopted Java code falls into three categories:
+
+- bootclasspath
+- system server
+- apps and libraries
+
+Dexpreopt implementation for bootclasspath libraries (boot images) is located in
+[soong/java] (see e.g. [soong/java/dexpreopt_bootjars.go]), and install rules
+are in [make/core/dex_preopt.mk].
+
+Dexpreopt implementation for system server, libraries and apps is located in
+[soong/dexpreopt]. For the rest of this section we focus primarily on it (and
+not boot images).
+
+Dexpeopt implementation is split across the Soong part and the Make part. The
+core logic is in Soong, and Make only generates configs and scripts to pass
+information to Soong.
+
+### Global and module dexpreopt.config
+
+The build system generates a global JSON dexpreopt config that is populated from
+product variables. This is static configuration that is passed to both Soong and
+Make. The `$OUT/soong/dexpreopt.config` file is generated in
+[make/core/dex_preopt_config.mk]. Soong reads it in [soong/dexpreopt/config.go]
+and makes a device-specific copy (this is needed to ensure incremental build
+correctness). The global config contains lists of bootclasspath jars, system
+server jars, dex2oat options, global switches that enable and disable parts of
+dexpreopt and so on.
+
+The build system also generates a module config for each dexpreopted package. It
+contains package-specific configuration that is derived from the global
+configuration and Android.bp or Android.mk module for the package.
+
+Module configs for Make packages are generated in
+[make/core/dex_preopt_odex_install.mk]; they are materialized as per-package
+JSON dexpreopt.config files.
+
+Module configs in Soong are not materialized as dexpreopt.config files and exist
+as Go structures in memory, unless it is necessary to materialize them as a file
+for dependent Make packages or for post-dexpreopting. Module configs are defined
+in [soong/dexpreopt/config.go].
+
+### Dexpreopt in Soong
+
+The Soong implementation of dexpreopt consists roughly of the following steps:
+
+- Read global dexpreopt config passed from Make ([soong/dexpreopt/config.go]).
+
+- Construct a static boot image config ([soong/java/dexpreopt_config.go]).
+
+- During dependency mutator pass, for each suitable module:
+    - add uses-library dependencies (e.g. for apps: [soong/java/app.go:deps])
+
+- During rule generation pass, for each suitable module:
+    - compute transitive uses-library dependency closure
+      ([soong/java/java.go:addCLCFromDep])
+
+    - construct CLC from the dependency closure
+      ([soong/dexpreopt/class_loader_context.go])
+
+    - construct module config with CLC, boot image locations, etc.
+      ([soong/java/dexpreopt.go])
+
+    - generate build rules to verify build-time CLC against the manifest (e.g.
+      for apps: [soong/java/app.go:verifyUsesLibraries])
+
+    - generate dexpreopt build rule ([soong/dexpreopt/dexpreopt.go])
+
+- At the end of rule generation pass:
+    - generate build rules for boot images ([soong/java/dexpreopt_bootjars.go],
+      [soong/java/bootclasspath_fragment.go] and
+      [soong/java/platform_bootclasspath.go])
+
+### Dexpreopt in Make - dexpreopt_gen
+
+In order to reuse the same dexpreopt implementation for both Soong and Make
+packages, part of Soong is compiled into a standalone binary dexpreopt_gen. It
+runs during the Ninja stage of the build and generates shell scripts with
+dexpreopt build rules for Make packages, and then executes them.
+
+This setup causes many inconveniences. To name a few:
+
+- Errors in the build rules are only revealed at the late stage of the build.
+
+- These rules are not tested by the presubmit builds that run `m nothing` on
+  many build targets/products.
+
+- It is impossible to find dexpreopt build rules in the generated Ninja files.
+
+However all these issues are a lesser evil compared to having a duplicate
+dexpreopt implementation in Make. Also note that it would be problematic to
+reimplement the logic in Make anyway, because Android.mk modules are not
+processed in the order of uses-library dependencies and propagating dependency
+information from one module to another would require a similar workaround with
+a script.
+
+Dexpreopt for Make packages involves a few steps:
+
+- At Soong phase (during `m nothing`), see dexpreopt_gen:
+    - generate build rules for dexpreopt_gen binary
+
+- At Make/Kati phase (during `m nothing`), see
+  [make/core/dex_preopt_odex_install.mk]:
+    - generate build rules for module dexpreopt.config
+
+    - generate build rules for merging dependency dexpreopt.config files (see
+      [make/core/dex_preopt_config_merger.py])
+
+    - generate build rules for dexpreopt_gen invocation
+
+    - generate build rules for executing dexpreopt.sh scripts
+
+- At Ninja phase (during `m`):
+    - generate dexpreopt.config files
+
+    - execute dexpreopt_gen rules (generate dexpreopt.sh scripts)
+
+    - execute dexpreopt.sh scripts (this runs the actual dexpreopt)
+
+The Make/Kati phase adds all the necessary dependencies that trigger
+dexpreopt_gen and dexpreopt.sh rules. The real dexpreopt command (dex2oat
+invocation that will be executed to AOT-compile a package) is in the
+dexpreopt.sh script, which is generated close to the end of the build.
+
+### Indirect build rules
+
+The process described above for Make packages involves "indirect build rules",
+i.e. build rules that are generated not at the time when the build system is
+created (which is a small step at the very beginning of the build triggered with
+`m nothing`), but at the time when the actual build is done (`m` phase).
+
+Some build systems, such as Make, allow modifications of the build graph during
+the build. Other build systems, such as Soong, have a clear separation into the
+first "generation phase" (this is when build rules are created) and the second
+"build phase" (this is when the build rules are executed), and they do not allow
+modifications of the dependency graph during the second phase. The Soong
+approach is better from performance standpoint, because with the Make approach
+there are no guarantees regarding the time of the build --- recursive build
+graph modfications continue until fixpoint. However the Soong approach is also
+more restictive, as it can only generate build rules from the information that
+is passed to the build system via global configuration, Android.bp files or
+encoded in the Go code. Any other information (such as the contents of the Java
+manifest files) are not accessible and cannot be used to generate build rules.
+
+Hence the need for the "indirect build rules": during the generation phase only
+stubs of the build rules are generated, and the real rules are generated by the
+stub rules during the build phase (and executed immediately). Note that the
+build system still has to add all the necessary dependencies during the
+generation phase, because it will not be possible to change build order during
+the build phase.
+
+Indirect buils rules are used in a couple of places in dexpreopt:
+
+- [soong/scripts/manifest_check.py]: first to extract targetSdkVersion from the
+  manifest, and later to extract `<uses-library/>` tags from the manifest and
+  compare them to the uses-library list known to the build system
+
+- [soong/scripts/construct_context.py]: to trim compatibility libraries in CLC
+
+- [make/core/dex_preopt_config_merger.py]: to merge information from
+  dexpreopt.config files for uses-library dependencies into the dependent's
+  dexpreopt.config file (mostly the CLC)
+
+- autogenerated dexpreopt.sh scripts: to call dexpreopt_gen
+
+### Consistency check - manifest_check.py
+
+Because the information from the manifests has to be duplicated in the
+Android.bp/Android.mk files, there is a danger that it may get out of sync. To
+guard against that, the build system generates a rule that verifies
+uses-libraries: checks the metadata in the build files against the contents of a
+manifest. The manifest can be available as a source file, or as part of a
+prebuilt APK.
+
+The check is implemented in [soong/scripts/manifest_check.py].
+
+It is possible to turn off the check globally for a product by setting
+`PRODUCT_BROKEN_VERIFY_USES_LIBRARIES := true` in a product makefile, or for a
+particular build by setting `RELAX_USES_LIBRARY_CHECK=true`.
+
+### Compatibility libraries - construct_context.py
+
+Compatibility libraries are libraries that didn’t exist prior to a certain SDK
+version (say, `N`), but classes in them were in the bootclasspath jars, etc.,
+and in version `N` they have been separated into a standalone uses-library.
+Compatibility libraries should only be in the CLC of an app if its
+`targetSdkVersion` in the manifest is less than `N`.
+
+Currently compatibility libraries only affect apps (but not other libraries).
+
+The build system cannot see `targetSdkVersion` of an app at the time it
+generates dexpreopt build rules, so it doesn't know whether to add compatibility
+libaries to CLC or not. As a workaround, the build system includes all
+compatibility libraries regardless of the app version, and appends some extra
+logic to the dexpreopt rule that will extract `targetSdkVersion` from the
+manifest and filter CLC based on that version during Ninja stage of the build,
+immediately before executing the dexpreopt command (see the
+soong/scripts/construct_context.py script).
+
+As of the time of writing (January 2022), there are the following compatibility
+libraries:
+
+- org.apache.http.legacy (SDK 28)
+- android.hidl.base-V1.0-java (SDK 29)
+- android.hidl.manager-V1.0-java (SDK 29)
+- android.test.base (SDK 30)
+- android.test.mock (SDK 30)
+
+### Manifest fixer
+
+Sometimes uses-library tags are missing from the source manifest of a
+library/app. This may happen for example if one of the transitive dependencies
+of the library/app starts using another uses-library, and the library/app's
+manifest isn't updated to include it.
+
+Soong can compute some of the missing uses-library tags for a given library/app
+automatically as SDK libraries in the transitive dependency closure of the
+library/app. The closure is needed because a library/app may depend on a static
+library that may in turn depend on an SDK library (possibly transitively via
+another library).
+
+Not all uses-library tags can be computed in this way, because some of the
+uses-library dependencies are not SDK libraries, or they are not reachable via
+transitive dependency closure. But when possible, allowing Soong to calculate
+the manifest entries is less prone to errors and simplifies maintenance. For
+example, consider a situation when many apps use some static library that adds a
+new uses-library dependency -- all the apps will have to be updated. That is
+difficult to maintain.
+
+There is also a manifest merger, because sometimes the final manifest of an app
+is merged from a few dependency manifests, so the final manifest installed on
+devices contains a superset of uses-library tags of the source manifest of the
+app.
+
+
+[make/core/dex_preopt.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt.mk
+[make/core/dex_preopt_config.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_config.mk
+[make/core/dex_preopt_config_merger.py]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_config_merger.py
+[make/core/dex_preopt_odex_install.mk]: https://cs.android.com/android/platform/superproject/+/master:build/make/core/dex_preopt_odex_install.mk
+[soong/dexpreopt]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt
+[soong/dexpreopt/class_loader_context.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/class_loader_context.go
+[soong/dexpreopt/config.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/config.go
+[soong/dexpreopt/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/dexpreopt/dexpreopt.go
+[soong/java]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java
+[soong/java/app.go:deps]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20deps%22
+[soong/java/app.go:verifyUsesLibraries]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/app.go?q=%22func%20\(u%20*usesLibrary\)%20verifyUsesLibraries%22
+[soong/java/bootclasspath_fragment.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/bootclasspath_fragment.go
+[soong/java/dexpreopt.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt.go
+[soong/java/dexpreopt_bootjars.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt_bootjars.go
+[soong/java/dexpreopt_config.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/dexpreopt_config.go
+[soong/java/java.go:addCLCFromDep]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/java.go?q=%22func%20addCLCfromDep%22
+[soong/java/platform_bootclasspath.go]: https://cs.android.com/android/platform/superproject/+/master:build/soong/java/platform_bootclasspath.go
+[soong/scripts/construct_context.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/scripts/construct_context.py
+[soong/scripts/manifest_check.py]: https://cs.android.com/android/platform/superproject/+/master:build/soong/scripts/manifest_check.py
diff --git a/java/base.go b/java/base.go
index 8747039..9978a66 100644
--- a/java/base.go
+++ b/java/base.go
@@ -481,6 +481,8 @@
 	sdkVersion    android.SdkSpec
 	minSdkVersion android.SdkSpec
 	maxSdkVersion android.SdkSpec
+
+	sourceExtensions []string
 }
 
 func (j *Module) CheckStableSdkVersion(ctx android.BaseModuleContext) error {
@@ -982,6 +984,14 @@
 	return flags
 }
 
+func (j *Module) AddJSONData(d *map[string]interface{}) {
+	(&j.ModuleBase).AddJSONData(d)
+	(*d)["Java"] = map[string]interface{}{
+		"SourceExtensions": j.sourceExtensions,
+	}
+
+}
+
 func (j *Module) compile(ctx android.ModuleContext, aaptSrcJar android.Path) {
 	j.exportAidlIncludeDirs = android.PathsForModuleSrc(ctx, j.deviceProperties.Aidl.Export_include_dirs)
 
@@ -993,6 +1003,12 @@
 	}
 
 	srcFiles := android.PathsForModuleSrcExcludes(ctx, j.properties.Srcs, j.properties.Exclude_srcs)
+	j.sourceExtensions = []string{}
+	for _, ext := range []string{".kt", ".proto", ".aidl", ".java", ".logtags"} {
+		if hasSrcExt(srcFiles.Strings(), ext) {
+			j.sourceExtensions = append(j.sourceExtensions, ext)
+		}
+	}
 	if hasSrcExt(srcFiles.Strings(), ".proto") {
 		flags = protoFlags(ctx, &j.properties, &j.protoProperties, flags)
 	}
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 5fe409e..eddcb61 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -16,6 +16,7 @@
 
 import (
 	"fmt"
+	"io"
 	"path/filepath"
 	"reflect"
 	"strings"
@@ -588,6 +589,19 @@
 			// Provide the apex content info.
 			b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch)
 		}
+	} else {
+		// Versioned fragments are not needed by make.
+		b.HideFromMake()
+	}
+
+	// In order for information about bootclasspath_fragment modules to be added to module-info.json
+	// it is necessary to output an entry to Make. As bootclasspath_fragment modules are part of an
+	// APEX there can be multiple variants, including the default/platform variant and only one can
+	// be output to Make but it does not really matter which variant is output. The default/platform
+	// variant is the first (ctx.PrimaryModule()) and is usually hidden from make so this just picks
+	// the last variant (ctx.FinalModule()).
+	if ctx.Module() != ctx.FinalModule() {
+		b.HideFromMake()
 	}
 }
 
@@ -849,7 +863,22 @@
 }
 
 func (b *BootclasspathFragmentModule) AndroidMkEntries() []android.AndroidMkEntries {
-	var entriesList []android.AndroidMkEntries
+	// Use the generated classpath proto as the output.
+	outputFile := b.outputFilepath
+	// Create a fake entry that will cause this to be added to the module-info.json file.
+	entriesList := []android.AndroidMkEntries{{
+		Class:      "FAKE",
+		OutputFile: android.OptionalPathForPath(outputFile),
+		Include:    "$(BUILD_PHONY_PACKAGE)",
+		ExtraFooters: []android.AndroidMkExtraFootersFunc{
+			func(w io.Writer, name, prefix, moduleDir string) {
+				// Allow the bootclasspath_fragment to be built by simply passing its name on the command
+				// line.
+				fmt.Fprintln(w, ".PHONY:", b.Name())
+				fmt.Fprintln(w, b.Name()+":", outputFile.String())
+			},
+		},
+	}}
 	for _, install := range b.bootImageDeviceInstalls {
 		entriesList = append(entriesList, install.ToMakeEntries())
 	}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 421737b..2921c3e 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -336,7 +336,9 @@
 			FlagWithArg("--hide ", "SuperfluousPrefix").
 			FlagWithArg("--hide ", "AnnotationExtraction").
 			// b/222738070
-			FlagWithArg("--hide ", "BannedThrow")
+			FlagWithArg("--hide ", "BannedThrow").
+			// b/223382732
+			FlagWithArg("--hide ", "ChangedDefault")
 	}
 }
 
@@ -475,7 +477,9 @@
 		Flag("--format=v2").
 		FlagWithArg("--repeat-errors-max ", "10").
 		FlagWithArg("--hide ", "UnresolvedImport").
-		FlagWithArg("--hide ", "InvalidNullability")
+		FlagWithArg("--hide ", "InvalidNullability").
+		// b/223382732
+		FlagWithArg("--hide ", "ChangedDefault")
 
 	return cmd
 }
diff --git a/mk2rbc/mk2rbc.go b/mk2rbc/mk2rbc.go
index 74053fe..d8b88b2 100644
--- a/mk2rbc/mk2rbc.go
+++ b/mk2rbc/mk2rbc.go
@@ -50,15 +50,12 @@
 	soongNsPrefix = "SOONG_CONFIG_"
 
 	// And here are the functions and variables:
-	cfnGetCfg          = baseName + ".cfg"
-	cfnMain            = baseName + ".product_configuration"
-	cfnBoardMain       = baseName + ".board_configuration"
-	cfnPrintVars       = baseName + ".printvars"
-	cfnWarning         = baseName + ".warning"
-	cfnLocalAppend     = baseName + ".local_append"
-	cfnLocalSetDefault = baseName + ".local_set_default"
-	cfnInherit         = baseName + ".inherit"
-	cfnSetListDefault  = baseName + ".setdefault"
+	cfnGetCfg         = baseName + ".cfg"
+	cfnMain           = baseName + ".product_configuration"
+	cfnBoardMain      = baseName + ".board_configuration"
+	cfnPrintVars      = baseName + ".printvars"
+	cfnInherit        = baseName + ".inherit"
+	cfnSetListDefault = baseName + ".setdefault"
 )
 
 const (
@@ -465,17 +462,17 @@
 	return ctx
 }
 
-func (ctx *parseContext) lastAssignment(name string) *assignmentNode {
+func (ctx *parseContext) lastAssignment(v variable) *assignmentNode {
 	for va := ctx.varAssignments; va != nil; va = va.outer {
-		if v, ok := va.vars[name]; ok {
+		if v, ok := va.vars[v.name()]; ok {
 			return v
 		}
 	}
 	return nil
 }
 
-func (ctx *parseContext) setLastAssignment(name string, asgn *assignmentNode) {
-	ctx.varAssignments.vars[name] = asgn
+func (ctx *parseContext) setLastAssignment(v variable, asgn *assignmentNode) {
+	ctx.varAssignments.vars[v.name()] = asgn
 }
 
 func (ctx *parseContext) pushVarAssignments() {
@@ -532,7 +529,7 @@
 	if lhs == nil {
 		return []starlarkNode{ctx.newBadNode(a, "unknown variable %s", name)}
 	}
-	_, isTraced := ctx.tracedVariables[name]
+	_, isTraced := ctx.tracedVariables[lhs.name()]
 	asgn := &assignmentNode{lhs: lhs, mkValue: a.Value, isTraced: isTraced, location: ctx.errorLocation(a)}
 	if lhs.valueType() == starlarkTypeUnknown {
 		// Try to divine variable type from the RHS
@@ -565,17 +562,13 @@
 		}
 	}
 
-	asgn.previous = ctx.lastAssignment(name)
-	ctx.setLastAssignment(name, asgn)
+	asgn.previous = ctx.lastAssignment(lhs)
+	ctx.setLastAssignment(lhs, asgn)
 	switch a.Type {
 	case "=", ":=":
 		asgn.flavor = asgnSet
 	case "+=":
-		if asgn.previous == nil && !asgn.lhs.isPreset() {
-			asgn.flavor = asgnMaybeAppend
-		} else {
-			asgn.flavor = asgnAppend
-		}
+		asgn.flavor = asgnAppend
 	case "?=":
 		asgn.flavor = asgnMaybeSet
 	default:
@@ -1268,12 +1261,12 @@
 				args: []starlarkExpr{
 					&stringLiteralExpr{literal: substParts[0]},
 					&stringLiteralExpr{literal: substParts[1]},
-					NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil),
+					NewVariableRefExpr(v, ctx.lastAssignment(v) != nil),
 				},
 			}
 		}
 		if v := ctx.addVariable(refDump); v != nil {
-			return NewVariableRefExpr(v, ctx.lastAssignment(v.name()) != nil)
+			return NewVariableRefExpr(v, ctx.lastAssignment(v) != nil)
 		}
 		return ctx.newBadExpr(node, "unknown variable %s", refDump)
 	}
diff --git a/mk2rbc/mk2rbc_test.go b/mk2rbc/mk2rbc_test.go
index 55d48ff..35c54d2 100644
--- a/mk2rbc/mk2rbc_test.go
+++ b/mk2rbc/mk2rbc_test.go
@@ -65,6 +65,10 @@
 PRODUCT_NAME := Pixel 3
 PRODUCT_MODEL :=
 local_var = foo
+local-var-with-dashes := bar
+$(warning local-var-with-dashes: $(local-var-with-dashes))
+GLOBAL-VAR-WITH-DASHES := baz
+$(warning GLOBAL-VAR-WITH-DASHES: $(GLOBAL-VAR-WITH-DASHES))
 `,
 		expected: `load("//build/make/core:product_config.rbc", "rblf")
 
@@ -73,6 +77,10 @@
   cfg["PRODUCT_NAME"] = "Pixel 3"
   cfg["PRODUCT_MODEL"] = ""
   _local_var = "foo"
+  _local_var_with_dashes = "bar"
+  rblf.mkwarning("pixel3.mk", "local-var-with-dashes: %s" % _local_var_with_dashes)
+  g["GLOBAL-VAR-WITH-DASHES"] = "baz"
+  rblf.mkwarning("pixel3.mk", "GLOBAL-VAR-WITH-DASHES: %s" % g["GLOBAL-VAR-WITH-DASHES"])
 `,
 	},
 	{
@@ -893,6 +901,43 @@
 `,
 	},
 	{
+		desc:   "assigment setdefaults",
+		mkname: "product.mk",
+		in: `
+# All of these should have a setdefault because they're self-referential and not defined before
+PRODUCT_LIST1 = a $(PRODUCT_LIST1)
+PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
+PRODUCT_LIST3 += a
+
+# Now doing them again should not have a setdefault because they've already been set
+PRODUCT_LIST1 = a $(PRODUCT_LIST1)
+PRODUCT_LIST2 ?= a $(PRODUCT_LIST2)
+PRODUCT_LIST3 += a
+`,
+		expected: `# All of these should have a setdefault because they're self-referential and not defined before
+load("//build/make/core:product_config.rbc", "rblf")
+
+def init(g, handle):
+  cfg = rblf.cfg(handle)
+  rblf.setdefault(handle, "PRODUCT_LIST1")
+  cfg["PRODUCT_LIST1"] = (["a"] +
+      cfg.get("PRODUCT_LIST1", []))
+  if cfg.get("PRODUCT_LIST2") == None:
+    rblf.setdefault(handle, "PRODUCT_LIST2")
+    cfg["PRODUCT_LIST2"] = (["a"] +
+        cfg.get("PRODUCT_LIST2", []))
+  rblf.setdefault(handle, "PRODUCT_LIST3")
+  cfg["PRODUCT_LIST3"] += ["a"]
+  # Now doing them again should not have a setdefault because they've already been set
+  cfg["PRODUCT_LIST1"] = (["a"] +
+      cfg["PRODUCT_LIST1"])
+  if cfg.get("PRODUCT_LIST2") == None:
+    cfg["PRODUCT_LIST2"] = (["a"] +
+        cfg["PRODUCT_LIST2"])
+  cfg["PRODUCT_LIST3"] += ["a"]
+`,
+	},
+	{
 		desc:   "soong namespace assignments",
 		mkname: "product.mk",
 		in: `
@@ -985,6 +1030,7 @@
 def init(g, handle):
   cfg = rblf.cfg(handle)
   if "hwaddress" not in cfg.get("PRODUCT_PACKAGES", []):
+    rblf.setdefault(handle, "PRODUCT_PACKAGES")
     cfg["PRODUCT_PACKAGES"] = (rblf.mkstrip("%s hwaddress" % " ".join(cfg.get("PRODUCT_PACKAGES", [])))).split()
 `,
 	},
diff --git a/mk2rbc/node.go b/mk2rbc/node.go
index 5d98d7b..9d5af91 100644
--- a/mk2rbc/node.go
+++ b/mk2rbc/node.go
@@ -184,10 +184,9 @@
 
 const (
 	// Assignment flavors
-	asgnSet         assignmentFlavor = iota // := or =
-	asgnMaybeSet    assignmentFlavor = iota // ?= and variable may be unset
-	asgnAppend      assignmentFlavor = iota // += and variable has been set before
-	asgnMaybeAppend assignmentFlavor = iota // += and variable may be unset
+	asgnSet      assignmentFlavor = iota // := or =
+	asgnMaybeSet assignmentFlavor = iota // ?=
+	asgnAppend   assignmentFlavor = iota // +=
 )
 
 type assignmentNode struct {
@@ -215,6 +214,20 @@
 	}
 }
 
+func (asgn *assignmentNode) isSelfReferential() bool {
+	if asgn.flavor == asgnAppend {
+		return true
+	}
+	isSelfReferential := false
+	asgn.value.transform(func(expr starlarkExpr) starlarkExpr {
+		if ref, ok := expr.(*variableRefExpr); ok && ref.ref.name() == asgn.lhs.name() {
+			isSelfReferential = true
+		}
+		return nil
+	})
+	return isSelfReferential
+}
+
 type exprNode struct {
 	expr starlarkExpr
 }
diff --git a/mk2rbc/variable.go b/mk2rbc/variable.go
index f7adca5..3241a38 100644
--- a/mk2rbc/variable.go
+++ b/mk2rbc/variable.go
@@ -88,25 +88,36 @@
 		}
 		value.emit(gctx)
 	}
-
-	switch asgn.flavor {
-	case asgnSet:
-		emitAssignment()
-	case asgnAppend:
-		emitAppend()
-	case asgnMaybeAppend:
-		// If we are not sure variable has been assigned before, emit setdefault
+	emitSetDefault := func() {
 		if pcv.typ == starlarkTypeList {
 			gctx.writef("%s(handle, %q)", cfnSetListDefault, pcv.name())
 		} else {
 			gctx.writef("cfg.setdefault(%q, %s)", pcv.name(), pcv.defaultValueString())
 		}
 		gctx.newLine()
+	}
+
+	// If we are not sure variable has been assigned before, emit setdefault
+	needsSetDefault := asgn.previous == nil && !pcv.isPreset() && asgn.isSelfReferential()
+
+	switch asgn.flavor {
+	case asgnSet:
+		if needsSetDefault {
+			emitSetDefault()
+		}
+		emitAssignment()
+	case asgnAppend:
+		if needsSetDefault {
+			emitSetDefault()
+		}
 		emitAppend()
 	case asgnMaybeSet:
 		gctx.writef("if cfg.get(%q) == None:", pcv.nam)
 		gctx.indentLevel++
 		gctx.newLine()
+		if needsSetDefault {
+			emitSetDefault()
+		}
 		emitAssignment()
 		gctx.indentLevel--
 	}
@@ -121,7 +132,7 @@
 }
 
 func (pcv productConfigVariable) emitDefined(gctx *generationContext) {
-	gctx.writef("g.get(%q) != None", pcv.name())
+	gctx.writef("cfg.get(%q) != None", pcv.name())
 }
 
 type otherGlobalVariable struct {
@@ -146,20 +157,30 @@
 		value.emit(gctx)
 	}
 
+	// If we are not sure variable has been assigned before, emit setdefault
+	needsSetDefault := asgn.previous == nil && !scv.isPreset() && asgn.isSelfReferential()
+
 	switch asgn.flavor {
 	case asgnSet:
+		if needsSetDefault {
+			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
+			gctx.newLine()
+		}
 		emitAssignment()
 	case asgnAppend:
-		emitAppend()
-	case asgnMaybeAppend:
-		// If we are not sure variable has been assigned before, emit setdefault
-		gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
-		gctx.newLine()
+		if needsSetDefault {
+			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
+			gctx.newLine()
+		}
 		emitAppend()
 	case asgnMaybeSet:
 		gctx.writef("if g.get(%q) == None:", scv.nam)
 		gctx.indentLevel++
 		gctx.newLine()
+		if needsSetDefault {
+			gctx.writef("g.setdefault(%q, %s)", scv.name(), scv.defaultValueString())
+			gctx.newLine()
+		}
 		emitAssignment()
 		gctx.indentLevel--
 	}
@@ -191,7 +212,7 @@
 
 func (lv localVariable) emitSet(gctx *generationContext, asgn *assignmentNode) {
 	switch asgn.flavor {
-	case asgnSet:
+	case asgnSet, asgnMaybeSet:
 		gctx.writef("%s = ", lv)
 		asgn.value.emitListVarCopy(gctx)
 	case asgnAppend:
@@ -203,14 +224,6 @@
 			value = &toStringExpr{expr: value}
 		}
 		value.emit(gctx)
-	case asgnMaybeAppend:
-		gctx.writef("%s(%q, ", cfnLocalAppend, lv)
-		asgn.value.emit(gctx)
-		gctx.write(")")
-	case asgnMaybeSet:
-		gctx.writef("%s(%q, ", cfnLocalSetDefault, lv)
-		asgn.value.emit(gctx)
-		gctx.write(")")
 	}
 }
 
@@ -278,6 +291,14 @@
 // addVariable returns a variable with a given name. A variable is
 // added if it does not exist yet.
 func (ctx *parseContext) addVariable(name string) variable {
+	// Heuristics: if variable's name is all lowercase, consider it local
+	// string variable.
+	isLocalVariable := name == strings.ToLower(name)
+	// Local variables can't have special characters in them, because they
+	// will be used as starlark identifiers
+	if isLocalVariable {
+		name = strings.ReplaceAll(strings.TrimSpace(name), "-", "_")
+	}
 	v, found := ctx.variables[name]
 	if !found {
 		_, preset := presetVariables[name]
@@ -288,9 +309,7 @@
 			case VarClassSoong:
 				v = &otherGlobalVariable{baseVariable{nam: name, typ: vi.valueType, preset: preset}}
 			}
-		} else if name == strings.ToLower(name) {
-			// Heuristics: if variable's name is all lowercase, consider it local
-			// string variable.
+		} else if isLocalVariable {
 			v = &localVariable{baseVariable{nam: name, typ: starlarkTypeUnknown}}
 		} else {
 			vt := starlarkTypeUnknown
diff --git a/python/python.go b/python/python.go
index 734ac57..b100cc3 100644
--- a/python/python.go
+++ b/python/python.go
@@ -423,6 +423,9 @@
 		if ctx.Target().Os.Bionic() {
 			launcherSharedLibDeps = append(launcherSharedLibDeps, "libc", "libdl", "libm")
 		}
+		if ctx.Target().Os == android.LinuxMusl && !ctx.Config().HostStaticBinaries() {
+			launcherSharedLibDeps = append(launcherSharedLibDeps, "libc_musl")
+		}
 
 		switch p.properties.Actual_version {
 		case pyVersion2:
@@ -432,6 +435,7 @@
 			if p.bootstrapper.autorun() {
 				launcherModule = "py2-launcher-autorun"
 			}
+
 			launcherSharedLibDeps = append(launcherSharedLibDeps, "libc++")
 
 		case pyVersion3:
@@ -441,6 +445,9 @@
 			if p.bootstrapper.autorun() {
 				launcherModule = "py3-launcher-autorun"
 			}
+			if ctx.Config().HostStaticBinaries() && ctx.Target().Os == android.LinuxMusl {
+				launcherModule += "-static"
+			}
 
 			if ctx.Device() {
 				launcherSharedLibDeps = append(launcherSharedLibDeps, "liblog")
diff --git a/rust/compiler.go b/rust/compiler.go
index c5d40f4..19499fa 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -121,6 +121,12 @@
 	// include all of the static libraries symbols in any dylibs or binaries which use this rlib as well.
 	Whole_static_libs []string `android:"arch_variant"`
 
+	// list of Rust system library dependencies.
+	//
+	// This is usually only needed when `no_stdlibs` is true, in which case it can be used to depend on system crates
+	// like `core` and `alloc`.
+	Stdlibs []string `android:"arch_variant"`
+
 	// crate name, required for modules which produce Rust libraries: rust_library, rust_ffi and SourceProvider
 	// modules which create library variants (rust_bindgen). This must be the expected extern crate name used in
 	// source, and is required to conform to an enforced format matching library output files (if the output file is
@@ -360,6 +366,7 @@
 	deps.StaticLibs = append(deps.StaticLibs, compiler.Properties.Static_libs...)
 	deps.WholeStaticLibs = append(deps.WholeStaticLibs, compiler.Properties.Whole_static_libs...)
 	deps.SharedLibs = append(deps.SharedLibs, compiler.Properties.Shared_libs...)
+	deps.Stdlibs = append(deps.Stdlibs, compiler.Properties.Stdlibs...)
 
 	if !Bool(compiler.Properties.No_stdlibs) {
 		for _, stdlib := range config.Stdlibs {
diff --git a/rust/config/allowed_list.go b/rust/config/allowed_list.go
index 14fcb02..bc36b20 100644
--- a/rust/config/allowed_list.go
+++ b/rust/config/allowed_list.go
@@ -24,6 +24,7 @@
 		"packages/modules/DnsResolver",
 		"packages/modules/Uwb",
 		"packages/modules/Virtualization",
+		"platform_testing/tests/codecoverage/native/rust",
 		"prebuilts/rust",
 		"system/core/libstats/pull_rust",
 		"system/extras/profcollectd",
diff --git a/rust/config/toolchain.go b/rust/config/toolchain.go
index a769f12..9c9d572 100644
--- a/rust/config/toolchain.go
+++ b/rust/config/toolchain.go
@@ -121,14 +121,7 @@
 }
 
 func LibclangRuntimeLibrary(t Toolchain, library string) string {
-	arch := t.LibclangRuntimeLibraryArch()
-	if arch == "" {
-		return ""
-	}
-	if !t.Bionic() {
-		return "libclang_rt." + library + "-" + arch
-	}
-	return "libclang_rt." + library + "-" + arch + "-android"
+	return "libclang_rt." + library
 }
 
 func LibRustRuntimeLibrary(t Toolchain, library string) string {
diff --git a/rust/coverage.go b/rust/coverage.go
index 050b811..651ce6e 100644
--- a/rust/coverage.go
+++ b/rust/coverage.go
@@ -22,6 +22,7 @@
 
 var CovLibraryName = "libprofile-clang-extras"
 
+// Add '%c' to default specifier after we resolve http://b/210012154
 const profileInstrFlag = "-fprofile-instr-generate=/data/misc/trace/clang-%p-%m.profraw"
 
 type coverage struct {
@@ -59,6 +60,10 @@
 		flags.LinkFlags = append(flags.LinkFlags,
 			profileInstrFlag, "-g", coverage.OutputFile().Path().String(), "-Wl,--wrap,open")
 		deps.StaticLibs = append(deps.StaticLibs, coverage.OutputFile().Path())
+		if cc.EnableContinuousCoverage(ctx) {
+			flags.RustFlags = append(flags.RustFlags, "-C llvm-args=--runtime-counter-relocation")
+			flags.LinkFlags = append(flags.LinkFlags, "-Wl,-mllvm,-runtime-counter-relocation")
+		}
 	}
 
 	return flags, deps
diff --git a/rust/image.go b/rust/image.go
index 5d57f15..dfc7f74 100644
--- a/rust/image.go
+++ b/rust/image.go
@@ -149,6 +149,10 @@
 	return mod.ModuleBase.InRecovery() || mod.ModuleBase.InstallInRecovery()
 }
 
+func (mod *Module) InRamdisk() bool {
+	return mod.ModuleBase.InRamdisk() || mod.ModuleBase.InstallInRamdisk()
+}
+
 func (mod *Module) InVendorRamdisk() bool {
 	return mod.ModuleBase.InVendorRamdisk() || mod.ModuleBase.InstallInVendorRamdisk()
 }
diff --git a/rust/rust.go b/rust/rust.go
index f40f1a8..1c718a4 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -968,6 +968,7 @@
 	deps.ProcMacros = android.LastUniqueStrings(deps.ProcMacros)
 	deps.SharedLibs = android.LastUniqueStrings(deps.SharedLibs)
 	deps.StaticLibs = android.LastUniqueStrings(deps.StaticLibs)
+	deps.Stdlibs = android.LastUniqueStrings(deps.Stdlibs)
 	deps.WholeStaticLibs = android.LastUniqueStrings(deps.WholeStaticLibs)
 	return deps
 
diff --git a/rust/testing.go b/rust/testing.go
index 1b34dfe..cb98bed 100644
--- a/rust/testing.go
+++ b/rust/testing.go
@@ -88,13 +88,13 @@
 			export_include_dirs: ["libprotobuf-cpp-full-includes"],
 		}
 		cc_library {
-			name: "libclang_rt.asan-aarch64-android",
+			name: "libclang_rt.asan",
 			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
 		}
 		cc_library {
-			name: "libclang_rt.hwasan_static-aarch64-android",
+			name: "libclang_rt.hwasan_static",
 			no_libcrt: true,
 			nocrt: true,
 			system_shared_libs: [],
diff --git a/rust/vendor_snapshot_test.go b/rust/vendor_snapshot_test.go
index 03bd867..7be0042 100644
--- a/rust/vendor_snapshot_test.go
+++ b/rust/vendor_snapshot_test.go
@@ -561,7 +561,7 @@
 				static_libs: [
 					"libvendor",
 					"libvndk",
-					"libclang_rt.builtins-aarch64-android",
+					"libclang_rt.builtins",
 					"note_memtag_heap_sync",
 				],
 				shared_libs: [
@@ -589,7 +589,7 @@
 				static_libs: [
 					"libvendor",
 					"libvndk",
-					"libclang_rt.builtins-arm-android",
+					"libclang_rt.builtins",
 				],
 				shared_libs: [
 					"libvendor_available",
@@ -731,19 +731,7 @@
 	}
 
 	vendor_snapshot_static {
-		name: "libclang_rt.builtins-aarch64-android",
-		version: "30",
-		target_arch: "arm64",
-		vendor: true,
-		arch: {
-			arm64: {
-				src: "libclang_rt.builtins-aarch64-android.a",
-			},
-		},
-    }
-
-    vendor_snapshot_static {
-		name: "libclang_rt.builtins-arm-android",
+		name: "libclang_rt.builtins",
 		version: "30",
 		target_arch: "arm64",
 		vendor: true,
@@ -751,6 +739,9 @@
 			arm: {
 				src: "libclang_rt.builtins-arm-android.a",
 			},
+			arm64: {
+				src: "libclang_rt.builtins-aarch64-android.a",
+			},
 		},
     }
 
@@ -967,7 +958,7 @@
 	}
 
 	libclientAndroidMkStaticLibs := ctx.ModuleForTests("libclient", sharedVariant).Module().(*Module).Properties.AndroidMkStaticLibs
-	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot", "libclang_rt.builtins-aarch64-android.vendor"}; !reflect.DeepEqual(g, w) {
+	if g, w := libclientAndroidMkStaticLibs, []string{"libvendor", "libvendor_without_snapshot", "libclang_rt.builtins.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted libclient AndroidMkStaticLibs %q, got %q", w, g)
 	}
 
@@ -1024,7 +1015,7 @@
 	}
 
 	memtagStaticLibs := ctx.ModuleForTests("memtag_binary", "android_vendor.30_arm64_armv8-a").Module().(*Module).Properties.AndroidMkStaticLibs
-	if g, w := memtagStaticLibs, []string{"libclang_rt.builtins-aarch64-android.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
+	if g, w := memtagStaticLibs, []string{"libclang_rt.builtins.vendor", "note_memtag_heap_sync.vendor"}; !reflect.DeepEqual(g, w) {
 		t.Errorf("wanted memtag_binary AndroidMkStaticLibs %q, got %q", w, g)
 	}
 }
diff --git a/scripts/hiddenapi/Android.bp b/scripts/hiddenapi/Android.bp
index 7ffda62..8a47c5d 100644
--- a/scripts/hiddenapi/Android.bp
+++ b/scripts/hiddenapi/Android.bp
@@ -69,10 +69,37 @@
     },
 }
 
+python_library_host {
+    name: "signature_trie",
+    srcs: ["signature_trie.py"],
+}
+
+python_test_host {
+    name: "signature_trie_test",
+    main: "signature_trie_test.py",
+    srcs: ["signature_trie_test.py"],
+    libs: ["signature_trie"],
+    version: {
+        py2: {
+            enabled: false,
+        },
+        py3: {
+            enabled: true,
+            embedded_launcher: true,
+        },
+    },
+    test_options: {
+        unit_test: true,
+    },
+}
+
 python_binary_host {
     name: "verify_overlaps",
     main: "verify_overlaps.py",
     srcs: ["verify_overlaps.py"],
+    libs: [
+        "signature_trie",
+    ],
     version: {
         py2: {
             enabled: false,
@@ -91,6 +118,9 @@
         "verify_overlaps.py",
         "verify_overlaps_test.py",
     ],
+    libs: [
+        "signature_trie",
+    ],
     version: {
         py2: {
             enabled: false,
diff --git a/scripts/hiddenapi/signature_trie.py b/scripts/hiddenapi/signature_trie.py
new file mode 100644
index 0000000..2ea8c49
--- /dev/null
+++ b/scripts/hiddenapi/signature_trie.py
@@ -0,0 +1,256 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 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.
+"""Verify that one set of hidden API flags is a subset of another."""
+import dataclasses
+import typing
+
+from itertools import chain
+
+
+@dataclasses.dataclass()
+class Node:
+
+    def values(self, selector):
+        """Get the values from a set of selected nodes.
+
+        :param selector: a function that can be applied to a key in the nodes
+            attribute to determine whether to return its values.
+
+        :return: A list of iterables of all the values associated with
+            this node and its children.
+        """
+        raise NotImplementedError("Please Implement this method")
+
+    def append_values(self, values, selector):
+        """Append the values associated with this node and its children.
+
+        For each item (key, child) in nodes the child node's values are returned
+        if and only if the selector returns True when called on its key. A child
+        node's values are all the values associated with it and all its
+        descendant nodes.
+
+        :param selector: a function that can be applied to a key in the nodes
+        attribute to determine whether to return its values.
+        :param values: a list of a iterables of values.
+        """
+        raise NotImplementedError("Please Implement this method")
+
+
+# pylint: disable=line-too-long
+@dataclasses.dataclass()
+class InteriorNode(Node):
+    """An interior node in a trie.
+
+    Each interior node has a dict that maps from an element of a signature to
+    either another interior node or a leaf. Each interior node represents either
+    a package, class or nested class. Class members are represented by a Leaf.
+
+    Associating the set of flags [public-api] with the signature
+    "Ljava/lang/Object;->String()Ljava/lang/String;" will cause the following
+    nodes to be created:
+    Node()
+    ^- package:java -> Node()
+       ^- package:lang -> Node()
+           ^- class:Object -> Node()
+              ^- member:String()Ljava/lang/String; -> Leaf([public-api])
+
+    Associating the set of flags [blocked,core-platform-api] with the signature
+    "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;"
+    will cause the following nodes to be created:
+    Node()
+    ^- package:java -> Node()
+       ^- package:lang -> Node()
+           ^- class:Character -> Node()
+              ^- class:UnicodeScript -> Node()
+                 ^- member:of(I)Ljava/lang/Character$UnicodeScript;
+                    -> Leaf([blocked,core-platform-api])
+    """
+
+    # pylint: enable=line-too-long
+
+    # A dict from an element of the signature to the Node/Leaf containing the
+    # next element/value.
+    nodes: typing.Dict[str, Node] = dataclasses.field(default_factory=dict)
+
+    # pylint: disable=line-too-long
+    @staticmethod
+    def signature_to_elements(signature):
+        """Split a signature or a prefix into a number of elements:
+
+        1. The packages (excluding the leading L preceding the first package).
+        2. The class names, from outermost to innermost.
+        3. The member signature.
+        e.g.
+        Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+        will be broken down into these elements:
+        1. package:java
+        2. package:lang
+        3. class:Character
+        4. class:UnicodeScript
+        5. member:of(I)Ljava/lang/Character$UnicodeScript;
+        """
+        # Remove the leading L.
+        #  - java/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+        text = signature.removeprefix("L")
+        # Split the signature between qualified class name and the class member
+        # signature.
+        #  0 - java/lang/Character$UnicodeScript
+        #  1 - of(I)Ljava/lang/Character$UnicodeScript;
+        parts = text.split(";->")
+        member = parts[1:]
+        # Split the qualified class name into packages, and class name.
+        #  0 - java
+        #  1 - lang
+        #  2 - Character$UnicodeScript
+        elements = parts[0].split("/")
+        packages = elements[0:-1]
+        class_name = elements[-1]
+        if class_name in ("*", "**"):  # pylint: disable=no-else-return
+            # Cannot specify a wildcard and target a specific member
+            if len(member) != 0:
+                raise Exception(f"Invalid signature {signature}: contains "
+                                f"wildcard {class_name} and "
+                                f"member signature {member[0]}")
+            wildcard = [class_name]
+            # Assemble the parts into a single list, adding prefixes to identify
+            # the different parts.
+            #  0 - package:java
+            #  1 - package:lang
+            #  2 - *
+            return list(chain(["package:" + x for x in packages], wildcard))
+        else:
+            # Split the class name into outer / inner classes
+            #  0 - Character
+            #  1 - UnicodeScript
+            classes = class_name.split("$")
+            # Assemble the parts into a single list, adding prefixes to identify
+            # the different parts.
+            #  0 - package:java
+            #  1 - package:lang
+            #  2 - class:Character
+            #  3 - class:UnicodeScript
+            #  4 - member:of(I)Ljava/lang/Character$UnicodeScript;
+            return list(
+                chain(["package:" + x for x in packages],
+                      ["class:" + x for x in classes],
+                      ["member:" + x for x in member]))
+
+    # pylint: enable=line-too-long
+
+    def add(self, signature, value):
+        """Associate the value with the specific signature.
+
+        :param signature: the member signature
+        :param value: the value to associated with the signature
+        :return: n/a
+        """
+        # Split the signature into elements.
+        elements = self.signature_to_elements(signature)
+        # Find the Node associated with the deepest class.
+        node = self
+        for element in elements[:-1]:
+            if element in node.nodes:
+                node = node.nodes[element]
+            else:
+                next_node = InteriorNode()
+                node.nodes[element] = next_node
+                node = next_node
+        # Add a Leaf containing the value and associate it with the member
+        # signature within the class.
+        last_element = elements[-1]
+        if not last_element.startswith("member:"):
+            raise Exception(
+                f"Invalid signature: {signature}, does not identify a "
+                "specific member")
+        if last_element in node.nodes:
+            raise Exception(f"Duplicate signature: {signature}")
+        node.nodes[last_element] = Leaf(value)
+
+    def get_matching_rows(self, pattern):
+        """Get the values (plural) associated with the pattern.
+
+        e.g. If the pattern is a full signature then this will return a list
+        containing the value associated with that signature.
+
+        If the pattern is a class then this will return a list containing the
+        values associated with all members of that class.
+
+        If the pattern is a package then this will return a list containing the
+        values associated with all the members of all the classes in that
+        package and sub-packages.
+
+        If the pattern ends with "*" then the preceding part is treated as a
+        package and this will return a list containing the values associated
+        with all the members of all the classes in that package.
+
+        If the pattern ends with "**" then the preceding part is treated
+        as a package and this will return a list containing the values
+        associated with all the members of all the classes in that package and
+        all sub-packages.
+
+        :param pattern: the pattern which could be a complete signature or a
+        class, or package wildcard.
+        :return: an iterable containing all the values associated with the
+        pattern.
+        """
+        elements = self.signature_to_elements(pattern)
+        node = self
+
+        # Include all values from this node and all its children.
+        selector = lambda x: True
+
+        last_element = elements[-1]
+        if last_element in ("*", "**"):
+            elements = elements[:-1]
+            if last_element == "*":
+                # Do not include values from sub-packages.
+                selector = lambda x: not x.startswith("package:")
+
+        for element in elements:
+            if element in node.nodes:
+                node = node.nodes[element]
+            else:
+                return []
+        return chain.from_iterable(node.values(selector))
+
+    def values(self, selector):
+        values = []
+        self.append_values(values, selector)
+        return values
+
+    def append_values(self, values, selector):
+        for key, node in self.nodes.items():
+            if selector(key):
+                node.append_values(values, lambda x: True)
+
+
+
+@dataclasses.dataclass()
+class Leaf(Node):
+    """A leaf of the trie"""
+
+    # The value associated with this leaf.
+    value: typing.Any
+
+    def values(self, selector):
+        return [[self.value]]
+
+    def append_values(self, values, selector):
+        values.append([self.value])
+
+
+def signature_trie():
+    return InteriorNode()
diff --git a/scripts/hiddenapi/signature_trie_test.py b/scripts/hiddenapi/signature_trie_test.py
new file mode 100755
index 0000000..2dc79d0
--- /dev/null
+++ b/scripts/hiddenapi/signature_trie_test.py
@@ -0,0 +1,192 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2022 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 verify_overlaps_test.py."""
+import io
+import unittest
+
+from signature_trie import InteriorNode
+from signature_trie import signature_trie
+
+
+class TestSignatureToElements(unittest.TestCase):
+
+    @staticmethod
+    def signature_to_elements(signature):
+        return InteriorNode.signature_to_elements(signature)
+
+    def test_nested_inner_classes(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "class:ProcessBuilder",
+            "class:Redirect",
+            "class:1",
+            "member:<init>()V",
+        ]
+        signature = "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_basic_member(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "class:Object",
+            "member:hashCode()I",
+        ]
+        signature = "Ljava/lang/Object;->hashCode()I"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_double_dollar_class(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "class:CharSequence",
+            "class:",
+            "class:ExternalSyntheticLambda0",
+            "member:<init>(Ljava/lang/CharSequence;)V",
+        ]
+        signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0;" \
+                    "-><init>(Ljava/lang/CharSequence;)V"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_no_member(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "class:CharSequence",
+            "class:",
+            "class:ExternalSyntheticLambda0",
+        ]
+        signature = "Ljava/lang/CharSequence$$ExternalSyntheticLambda0"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_wildcard(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "*",
+        ]
+        signature = "java/lang/*"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_recursive_wildcard(self):
+        elements = [
+            "package:java",
+            "package:lang",
+            "**",
+        ]
+        signature = "java/lang/**"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_no_packages_wildcard(self):
+        elements = [
+            "*",
+        ]
+        signature = "*"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_no_packages_recursive_wildcard(self):
+        elements = [
+            "**",
+        ]
+        signature = "**"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_non_standard_class_name(self):
+        elements = [
+            "package:javax",
+            "package:crypto",
+            "class:extObjectInputStream",
+        ]
+        signature = "Ljavax/crypto/extObjectInputStream"
+        self.assertEqual(elements, self.signature_to_elements(signature))
+
+    def test_invalid_pattern_wildcard_and_member(self):
+        pattern = "Ljava/lang/*;->hashCode()I"
+        with self.assertRaises(Exception) as context:
+            self.signature_to_elements(pattern)
+        self.assertIn("contains wildcard * and member signature hashCode()I",
+                      str(context.exception))
+
+
+class TestGetMatchingRows(unittest.TestCase):
+    extractInput = """
+Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
+Ljava/lang/Character;->serialVersionUID:J
+Ljava/lang/Object;->hashCode()I
+Ljava/lang/Object;->toString()Ljava/lang/String;
+Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V
+Ljava/util/zip/ZipFile;-><clinit>()V
+"""
+
+    def read_trie(self):
+        trie = signature_trie()
+        with io.StringIO(self.extractInput.strip()) as f:
+            for line in iter(f.readline, ""):
+                line = line.rstrip()
+                trie.add(line, line)
+        return trie
+
+    def check_patterns(self, pattern, expected):
+        trie = self.read_trie()
+        self.check_node_patterns(trie, pattern, expected)
+
+    def check_node_patterns(self, node, pattern, expected):
+        actual = list(node.get_matching_rows(pattern))
+        actual.sort()
+        self.assertEqual(expected, actual)
+
+    def test_member_pattern(self):
+        self.check_patterns("java/util/zip/ZipFile;-><clinit>()V",
+                            ["Ljava/util/zip/ZipFile;-><clinit>()V"])
+
+    def test_class_pattern(self):
+        self.check_patterns("java/lang/Object", [
+            "Ljava/lang/Object;->hashCode()I",
+            "Ljava/lang/Object;->toString()Ljava/lang/String;",
+        ])
+
+    # pylint: disable=line-too-long
+    def test_nested_class_pattern(self):
+        self.check_patterns("java/lang/Character", [
+            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
+            "Ljava/lang/Character;->serialVersionUID:J",
+        ])
+
+    def test_wildcard(self):
+        self.check_patterns("java/lang/*", [
+            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
+            "Ljava/lang/Character;->serialVersionUID:J",
+            "Ljava/lang/Object;->hashCode()I",
+            "Ljava/lang/Object;->toString()Ljava/lang/String;",
+            "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
+        ])
+
+    def test_recursive_wildcard(self):
+        self.check_patterns("java/**", [
+            "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;",
+            "Ljava/lang/Character;->serialVersionUID:J",
+            "Ljava/lang/Object;->hashCode()I",
+            "Ljava/lang/Object;->toString()Ljava/lang/String;",
+            "Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V",
+            "Ljava/util/zip/ZipFile;-><clinit>()V",
+        ])
+
+    # pylint: enable=line-too-long
+
+
+if __name__ == "__main__":
+    unittest.main(verbosity=2)
diff --git a/scripts/hiddenapi/verify_overlaps.py b/scripts/hiddenapi/verify_overlaps.py
index 4cd7e63..e5214df 100755
--- a/scripts/hiddenapi/verify_overlaps.py
+++ b/scripts/hiddenapi/verify_overlaps.py
@@ -13,239 +13,14 @@
 # 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.
-"""Verify that one set of hidden API flags is a subset of another.
-"""
+"""Verify that one set of hidden API flags is a subset of another."""
 
 import argparse
 import csv
 import sys
 from itertools import chain
 
-#pylint: disable=line-too-long
-class InteriorNode:
-    """An interior node in a trie.
-
-    Each interior node has a dict that maps from an element of a signature to
-    either another interior node or a leaf. Each interior node represents either
-    a package, class or nested class. Class members are represented by a Leaf.
-
-    Associating the set of flags [public-api] with the signature
-    "Ljava/lang/Object;->String()Ljava/lang/String;" will cause the following
-    nodes to be created:
-    Node()
-    ^- package:java -> Node()
-       ^- package:lang -> Node()
-           ^- class:Object -> Node()
-              ^- member:String()Ljava/lang/String; -> Leaf([public-api])
-
-    Associating the set of flags [blocked,core-platform-api] with the signature
-    "Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;"
-    will cause the following nodes to be created:
-    Node()
-    ^- package:java -> Node()
-       ^- package:lang -> Node()
-           ^- class:Character -> Node()
-              ^- class:UnicodeScript -> Node()
-                 ^- member:of(I)Ljava/lang/Character$UnicodeScript;
-                    -> Leaf([blocked,core-platform-api])
-
-    Attributes:
-        nodes: a dict from an element of the signature to the Node/Leaf
-          containing the next element/value.
-    """
-    #pylint: enable=line-too-long
-
-    def __init__(self):
-        self.nodes = {}
-
-    #pylint: disable=line-too-long
-    def signatureToElements(self, signature):
-        """Split a signature or a prefix into a number of elements:
-        1. The packages (excluding the leading L preceding the first package).
-        2. The class names, from outermost to innermost.
-        3. The member signature.
-        e.g.
-        Ljava/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
-        will be broken down into these elements:
-        1. package:java
-        2. package:lang
-        3. class:Character
-        4. class:UnicodeScript
-        5. member:of(I)Ljava/lang/Character$UnicodeScript;
-        """
-        # Remove the leading L.
-        #  - java/lang/Character$UnicodeScript;->of(I)Ljava/lang/Character$UnicodeScript;
-        text = signature.removeprefix("L")
-        # Split the signature between qualified class name and the class member
-        # signature.
-        #  0 - java/lang/Character$UnicodeScript
-        #  1 - of(I)Ljava/lang/Character$UnicodeScript;
-        parts = text.split(";->")
-        member = parts[1:]
-        # Split the qualified class name into packages, and class name.
-        #  0 - java
-        #  1 - lang
-        #  2 - Character$UnicodeScript
-        elements = parts[0].split("/")
-        packages = elements[0:-1]
-        className = elements[-1]
-        if className in ("*" , "**"): #pylint: disable=no-else-return
-            # Cannot specify a wildcard and target a specific member
-            if len(member) != 0:
-                raise Exception(
-                    "Invalid signature %s: contains wildcard %s and member " \
-                    "signature %s"
-                    % (signature, className, member[0]))
-            wildcard = [className]
-            # Assemble the parts into a single list, adding prefixes to identify
-            # the different parts.
-            #  0 - package:java
-            #  1 - package:lang
-            #  2 - *
-            return list(
-                chain(["package:" + x for x in packages], wildcard))
-        else:
-            # Split the class name into outer / inner classes
-            #  0 - Character
-            #  1 - UnicodeScript
-            classes = className.split("$")
-            # Assemble the parts into a single list, adding prefixes to identify
-            # the different parts.
-            #  0 - package:java
-            #  1 - package:lang
-            #  2 - class:Character
-            #  3 - class:UnicodeScript
-            #  4 - member:of(I)Ljava/lang/Character$UnicodeScript;
-            return list(
-                chain(
-                    ["package:" + x for x in packages],
-                    ["class:" + x for x in classes],
-                    ["member:" + x for x in member]))
-    #pylint: enable=line-too-long
-
-    def add(self, signature, value):
-        """Associate the value with the specific signature.
-
-        :param signature: the member signature
-        :param value: the value to associated with the signature
-        :return: n/a
-        """
-        # Split the signature into elements.
-        elements = self.signatureToElements(signature)
-        # Find the Node associated with the deepest class.
-        node = self
-        for element in elements[:-1]:
-            if element in node.nodes:
-                node = node.nodes[element]
-            else:
-                next_node = InteriorNode()
-                node.nodes[element] = next_node
-                node = next_node
-        # Add a Leaf containing the value and associate it with the member
-        # signature within the class.
-        lastElement = elements[-1]
-        if not lastElement.startswith("member:"):
-            raise Exception(
-                "Invalid signature: %s, does not identify a specific member" %
-                signature)
-        if lastElement in node.nodes:
-            raise Exception("Duplicate signature: %s" % signature)
-        node.nodes[lastElement] = Leaf(value)
-
-    def getMatchingRows(self, pattern):
-        """Get the values (plural) associated with the pattern.
-
-        e.g. If the pattern is a full signature then this will return a list
-        containing the value associated with that signature.
-
-        If the pattern is a class then this will return a list containing the
-        values associated with all members of that class.
-
-        If the pattern is a package then this will return a list containing the
-        values associated with all the members of all the classes in that
-        package and sub-packages.
-
-        If the pattern ends with "*" then the preceding part is treated as a
-        package and this will return a list containing the values associated
-        with all the members of all the classes in that package.
-
-        If the pattern ends with "**" then the preceding part is treated
-        as a package and this will return a list containing the values
-        associated with all the members of all the classes in that package and
-        all sub-packages.
-
-        :param pattern: the pattern which could be a complete signature or a
-        class, or package wildcard.
-        :return: an iterable containing all the values associated with the
-        pattern.
-        """
-        elements = self.signatureToElements(pattern)
-        node = self
-        # Include all values from this node and all its children.
-        selector = lambda x: True
-        lastElement = elements[-1]
-        if lastElement in ("*", "**"):
-            elements = elements[:-1]
-            if lastElement == "*":
-                # Do not include values from sub-packages.
-                selector = lambda x: not x.startswith("package:")
-        for element in elements:
-            if element in node.nodes:
-                node = node.nodes[element]
-            else:
-                return []
-        return chain.from_iterable(node.values(selector))
-
-    def values(self, selector):
-        """:param selector: a function that can be applied to a key in the nodes
-        attribute to determine whether to return its values.
-
-        :return: A list of iterables of all the values associated with
-        this node and its children.
-        """
-        values = []
-        self.appendValues(values, selector)
-        return values
-
-    def appendValues(self, values, selector):
-        """Append the values associated with this node and its children to the
-        list.
-
-        For each item (key, child) in nodes the child node's values are returned
-        if and only if the selector returns True when called on its key. A child
-        node's values are all the values associated with it and all its
-        descendant nodes.
-
-        :param selector: a function that can be applied to a key in the nodes
-        attribute to determine whether to return its values.
-        :param values: a list of a iterables of values.
-        """
-        for key, node in self.nodes.items():
-            if selector(key):
-                node.appendValues(values, lambda x: True)
-
-
-class Leaf:
-    """A leaf of the trie
-
-    Attributes:
-        value: the value associated with this leaf.
-    """
-
-    def __init__(self, value):
-        self.value = value
-
-    def values(self, selector): #pylint: disable=unused-argument
-        """:return: A list of a list of the value associated with this node.
-        """
-        return [[self.value]]
-
-    def appendValues(self, values, selector): #pylint: disable=unused-argument
-        """Appends a list of the value associated with this node to the list.
-
-        :param values: a list of a iterables of values.
-        """
-        values.append([self.value])
+from signature_trie import signature_trie
 
 
 def dict_reader(csvfile):
@@ -259,7 +34,7 @@
 
 
 def read_flag_trie_from_stream(stream):
-    trie = InteriorNode()
+    trie = signature_trie()
     reader = dict_reader(stream)
     for row in reader:
         signature = row["signature"]
@@ -269,8 +44,7 @@
 
 def extract_subset_from_monolithic_flags_as_dict_from_file(
         monolithicTrie, patternsFile):
-    """Extract a subset of flags from the dict containing all the monolithic
-    flags.
+    """Extract a subset of flags from the dict of monolithic flags.
 
     :param monolithicFlagsDict: the dict containing all the monolithic flags.
     :param patternsFile: a file containing a list of signature patterns that
@@ -284,8 +58,7 @@
 
 def extract_subset_from_monolithic_flags_as_dict_from_stream(
         monolithicTrie, stream):
-    """Extract a subset of flags from the trie containing all the monolithic
-    flags.
+    """Extract a subset of flags from the trie of monolithic flags.
 
     :param monolithicTrie: the trie containing all the monolithic flags.
     :param stream: a stream containing a list of signature patterns that define
@@ -295,7 +68,7 @@
     dict_signature_to_row = {}
     for pattern in stream:
         pattern = pattern.rstrip()
-        rows = monolithicTrie.getMatchingRows(pattern)
+        rows = monolithicTrie.get_matching_rows(pattern)
         for row in rows:
             signature = row["signature"]
             dict_signature_to_row[signature] = row
@@ -303,8 +76,10 @@
 
 
 def read_signature_csv_from_stream_as_dict(stream):
-    """Read the csv contents from the stream into a dict. The first column is
-    assumed to be the signature and used as the key.
+    """Read the csv contents from the stream into a dict.
+
+    The first column is assumed to be the signature and used as the
+    key.
 
     The whole row is stored as the value.
     :param stream: the csv contents to read
@@ -319,8 +94,10 @@
 
 
 def read_signature_csv_from_file_as_dict(csvFile):
-    """Read the csvFile into a dict. The first column is assumed to be the
-    signature and used as the key.
+    """Read the csvFile into a dict.
+
+    The first column is assumed to be the signature and used as the
+    key.
 
     The whole row is stored as the value.
     :param csvFile: the csv file to read
@@ -363,8 +140,7 @@
 def main(argv):
     args_parser = argparse.ArgumentParser(
         description="Verify that sets of hidden API flags are each a subset of "
-        "the monolithic flag file."
-    )
+        "the monolithic flag file.")
     args_parser.add_argument("monolithicFlags", help="The monolithic flag file")
     args_parser.add_argument(
         "modularFlags",
diff --git a/scripts/hiddenapi/verify_overlaps_test.py b/scripts/hiddenapi/verify_overlaps_test.py
index 22a1cdf..8cf2959 100755
--- a/scripts/hiddenapi/verify_overlaps_test.py
+++ b/scripts/hiddenapi/verify_overlaps_test.py
@@ -17,54 +17,9 @@
 import io
 import unittest
 
-from verify_overlaps import * #pylint: disable=unused-wildcard-import,wildcard-import
+from verify_overlaps import *  #pylint: disable=unused-wildcard-import,wildcard-import
 
 
-class TestSignatureToElements(unittest.TestCase):
-
-    def signatureToElements(self, signature):
-        return InteriorNode().signatureToElements(signature)
-
-    def test_signatureToElements_1(self):
-        expected = [
-            'package:java',
-            'package:lang',
-            'class:ProcessBuilder',
-            'class:Redirect',
-            'class:1',
-            'member:<init>()V',
-        ]
-        self.assertEqual(
-            expected,
-            self.signatureToElements(
-                'Ljava/lang/ProcessBuilder$Redirect$1;-><init>()V'))
-
-    def test_signatureToElements_2(self):
-        expected = [
-            'package:java',
-            'package:lang',
-            'class:Object',
-            'member:hashCode()I',
-        ]
-        self.assertEqual(
-            expected,
-            self.signatureToElements('Ljava/lang/Object;->hashCode()I'))
-
-    def test_signatureToElements_3(self):
-        expected = [
-            'package:java',
-            'package:lang',
-            'class:CharSequence',
-            'class:',
-            'class:ExternalSyntheticLambda0',
-            'member:<init>(Ljava/lang/CharSequence;)V',
-        ]
-        self.assertEqual(
-            expected,
-            self.signatureToElements(
-                'Ljava/lang/CharSequence$$ExternalSyntheticLambda0;'
-                '-><init>(Ljava/lang/CharSequence;)V'))
-
 #pylint: disable=line-too-long
 class TestDetectOverlaps(unittest.TestCase):
 
@@ -239,18 +194,6 @@
         }
         self.assertEqual(expected, subset)
 
-    def test_extract_subset_invalid_pattern_wildcard_and_member(self):
-        monolithic = self.read_flag_trie_from_string(
-            TestDetectOverlaps.extractInput)
-
-        patterns = 'Ljava/lang/*;->hashCode()I'
-
-        with self.assertRaises(Exception) as context:
-            self.extract_subset_from_monolithic_flags_as_dict_from_string(
-                monolithic, patterns)
-        self.assertTrue('contains wildcard * and member signature hashCode()I'
-                        in str(context.exception))
-
     def test_read_trie_duplicate(self):
         with self.assertRaises(Exception) as context:
             self.read_flag_trie_from_string("""
@@ -369,6 +312,8 @@
         mismatches = compare_signature_flags(monolithic, modular)
         expected = []
         self.assertEqual(expected, mismatches)
+
+
 #pylint: enable=line-too-long
 
 if __name__ == '__main__':