Merge "Remove macros that the Linux host no longer needs." into main
diff --git a/README.md b/README.md
index f471c47..93260e6 100644
--- a/README.md
+++ b/README.md
@@ -314,6 +314,9 @@
 * `["//visibility:override"]`: Discards any rules inherited from defaults or a
 creating module. Can only be used at the beginning of a list of visibility
 rules.
+* `["//visibility:any_partition"]`: Any modules of type android_filesystem
+or android_system_image can use this module. Intended for modules that no one
+should link against, but should still be included in soong-built partitions.
 * `["//some/package:__pkg__", "//other/package:__pkg__"]`: Only modules in
 `some/package` and `other/package` (defined in `some/package/*.bp` and
 `other/package/*.bp`) have access to this module. Note that sub-packages do not
diff --git a/aconfig/aconfig_declarations.go b/aconfig/aconfig_declarations.go
index 78f506a..392e819 100644
--- a/aconfig/aconfig_declarations.go
+++ b/aconfig/aconfig_declarations.go
@@ -40,6 +40,9 @@
 
 		// Container(system/vendor/apex) that this module belongs to
 		Container string
+
+		// The flags will only be repackaged if this prop is true.
+		Exportable bool
 	}
 
 	intermediatePath android.WritablePath
@@ -159,6 +162,7 @@
 	android.SetProvider(ctx, android.AconfigDeclarationsProviderKey, android.AconfigDeclarationsProviderData{
 		Package:                     module.properties.Package,
 		Container:                   module.properties.Container,
+		Exportable:                  module.properties.Exportable,
 		IntermediateCacheOutputPath: intermediateCacheFilePath,
 		IntermediateDumpOutputPath:  intermediateDumpFilePath,
 	})
diff --git a/aconfig/aconfig_declarations_test.go b/aconfig/aconfig_declarations_test.go
index d508af7..1fe3c86 100644
--- a/aconfig/aconfig_declarations_test.go
+++ b/aconfig/aconfig_declarations_test.go
@@ -27,6 +27,7 @@
 			name: "module_name",
 			package: "com.example.package",
 			container: "com.android.foo",
+			exportable: true,
 			srcs: [
 				"foo.aconfig",
 				"bar.aconfig",
@@ -41,6 +42,7 @@
 	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
 	android.AssertStringEquals(t, "package", depData.Package, "com.example.package")
 	android.AssertStringEquals(t, "container", depData.Container, "com.android.foo")
+	android.AssertBoolEquals(t, "exportable", depData.Exportable, true)
 	if !strings.HasSuffix(depData.IntermediateCacheOutputPath.String(), "/intermediate.pb") {
 		t.Errorf("Missing intermediates proto path in provider: %s", depData.IntermediateCacheOutputPath.String())
 	}
@@ -48,3 +50,22 @@
 		t.Errorf("Missing intermediates text path in provider: %s", depData.IntermediateDumpOutputPath.String())
 	}
 }
+
+func TestAconfigDeclarationsWithExportableUnset(t *testing.T) {
+	bp := `
+		aconfig_declarations {
+			name: "module_name",
+			package: "com.example.package",
+			container: "com.android.foo",
+			srcs: [
+				"foo.aconfig",
+				"bar.aconfig",
+			],
+		}
+	`
+	result := runTest(t, android.FixtureExpectsNoErrors, bp)
+
+	module := result.ModuleForTests("module_name", "").Module().(*DeclarationsModule)
+	depData, _ := android.SingletonModuleProvider(result, module, android.AconfigDeclarationsProviderKey)
+	android.AssertBoolEquals(t, "exportable", depData.Exportable, false)
+}
diff --git a/aconfig/codegen/java_aconfig_library.go b/aconfig/codegen/java_aconfig_library.go
index 4b8d346..d4c6da5 100644
--- a/aconfig/codegen/java_aconfig_library.go
+++ b/aconfig/codegen/java_aconfig_library.go
@@ -91,6 +91,12 @@
 	if !isModeSupported(mode) {
 		ctx.PropertyErrorf("mode", "%q is not a supported mode", mode)
 	}
+	// TODO: uncomment this part after internal clean up
+	//if mode == "exported" && !declarations.Exportable {
+	//	// if mode is exported, the corresponding aconfig_declaration must mark its
+	//	// exportable property true
+	//	ctx.PropertyErrorf("mode", "exported mode requires its aconfig_declaration has exportable prop true")
+	//}
 
 	ctx.Build(pctx, android.BuildParams{
 		Rule:        javaRule,
@@ -102,12 +108,15 @@
 		},
 	})
 
-	// Mark our generated code as possibly needing jarjar repackaging
-	// TODO: Maybe control this with a property?
-	module.AddJarJarRenameRule(declarations.Package+".Flags", "")
-	module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "")
-	module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "")
-	module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
+	if declarations.Exportable {
+		// Mark our generated code as possibly needing jarjar repackaging
+		// The repackaging only happens when the corresponding aconfig_declaration
+		// has property exportable true
+		module.AddJarJarRenameRule(declarations.Package+".Flags", "")
+		module.AddJarJarRenameRule(declarations.Package+".FeatureFlags", "")
+		module.AddJarJarRenameRule(declarations.Package+".FeatureFlagsImpl", "")
+		module.AddJarJarRenameRule(declarations.Package+".FakeFeatureFlagsImpl", "")
+	}
 
 	return srcJarPath
 }
diff --git a/aconfig/codegen/java_aconfig_library_test.go b/aconfig/codegen/java_aconfig_library_test.go
index 85d2675..de45b5c 100644
--- a/aconfig/codegen/java_aconfig_library_test.go
+++ b/aconfig/codegen/java_aconfig_library_test.go
@@ -176,6 +176,7 @@
 				name: "my_aconfig_declarations",
 				package: "com.example.package",
 				srcs: ["foo.aconfig"],
+				exportable: true,
 			}
 
 			java_aconfig_library {
diff --git a/aconfig/init.go b/aconfig/init.go
index 3e9d297..77f5ed3 100644
--- a/aconfig/init.go
+++ b/aconfig/init.go
@@ -43,7 +43,7 @@
 	// For create-device-config-sysprops: Generate aconfig flag value map text file
 	aconfigTextRule = pctx.AndroidStaticRule("aconfig_text",
 		blueprint.RuleParams{
-			Command: `${aconfig} dump-cache --format='{fully_qualified_name}={state:bool}'` +
+			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}'` +
 				` --cache ${in}` +
 				` --out ${out}.tmp` +
 				` && ( if cmp -s ${out}.tmp ${out} ; then rm ${out}.tmp ; else mv ${out}.tmp ${out} ; fi )`,
@@ -56,7 +56,7 @@
 	// For all_aconfig_declarations: Combine all parsed_flags proto files
 	AllDeclarationsRule = pctx.AndroidStaticRule("All_aconfig_declarations_dump",
 		blueprint.RuleParams{
-			Command: `${aconfig} dump-cache --format protobuf --out ${out} ${cache_files}`,
+			Command: `${aconfig} dump-cache --dedup --format protobuf --out ${out} ${cache_files}`,
 			CommandDeps: []string{
 				"${aconfig}",
 			},
@@ -73,7 +73,7 @@
 		blueprint.RuleParams{
 			Command: `rm -rf ${out}.tmp` +
 				`&& for cache in ${cache_files}; do ` +
-				`  if [ -n "$$(${aconfig} dump-cache --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` +
+				`  if [ -n "$$(${aconfig} dump-cache --dedup --cache $$cache --filter=is_exported:true --format='{fully_qualified_name}')" ]; then ` +
 				`    ${aconfig} create-java-lib --cache $$cache --mode=exported --out ${out}.tmp; ` +
 				`  fi ` +
 				`done` +
diff --git a/android/aconfig_providers.go b/android/aconfig_providers.go
index 1444e7d..74c1a5e 100644
--- a/android/aconfig_providers.go
+++ b/android/aconfig_providers.go
@@ -35,6 +35,7 @@
 type AconfigDeclarationsProviderData struct {
 	Package                     string
 	Container                   string
+	Exportable                  bool
 	IntermediateCacheOutputPath WritablePath
 	IntermediateDumpOutputPath  WritablePath
 }
diff --git a/android/config.go b/android/config.go
index f2dedad..f9cb842 100644
--- a/android/config.go
+++ b/android/config.go
@@ -210,6 +210,12 @@
 		Bool(c.config.productVariables.ReleaseDefaultModuleBuildFromSource)
 }
 
+// Enables flagged apis annotated with READ_WRITE aconfig flags to be included in the stubs
+// and hiddenapi flags so that they are accessible at runtime
+func (c Config) ReleaseExportRuntimeApis() bool {
+	return c.config.productVariables.GetBuildFlagBool("RELEASE_EXPORT_RUNTIME_APIS")
+}
+
 // Enables ABI monitoring of NDK libraries
 func (c Config) ReleaseNdkAbiMonitored() bool {
 	return c.config.productVariables.GetBuildFlagBool("RELEASE_NDK_ABI_MONITORED")
diff --git a/android/packaging.go b/android/packaging.go
index 8873540..a8fb28d 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -85,6 +85,7 @@
 
 	// GatherPackagingSpecs gathers PackagingSpecs of transitive dependencies.
 	GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec
+	GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec
 
 	// CopyDepsToZip zips the built artifacts of the dependencies into the given zip file and
 	// returns zip entries in it. This is expected to be called in GenerateAndroidBuildActions,
@@ -221,14 +222,18 @@
 	}
 }
 
-// See PackageModule.GatherPackagingSpecs
-func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
+func (p *PackagingBase) GatherPackagingSpecsWithFilter(ctx ModuleContext, filter func(PackagingSpec) bool) map[string]PackagingSpec {
 	m := make(map[string]PackagingSpec)
 	ctx.VisitDirectDeps(func(child Module) {
 		if pi, ok := ctx.OtherModuleDependencyTag(child).(PackagingItem); !ok || !pi.IsPackagingItem() {
 			return
 		}
 		for _, ps := range child.TransitivePackagingSpecs() {
+			if filter != nil {
+				if !filter(ps) {
+					continue
+				}
+			}
 			if _, ok := m[ps.relPathInPackage]; !ok {
 				m[ps.relPathInPackage] = ps
 			}
@@ -237,6 +242,11 @@
 	return m
 }
 
+// See PackageModule.GatherPackagingSpecs
+func (p *PackagingBase) GatherPackagingSpecs(ctx ModuleContext) map[string]PackagingSpec {
+	return p.GatherPackagingSpecsWithFilter(ctx, nil)
+}
+
 // CopySpecsToDir is a helper that will add commands to the rule builder to copy the PackagingSpec
 // entries into the specified directory.
 func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir WritablePath) (entries []string) {
diff --git a/android/rule_builder.go b/android/rule_builder.go
index e8dbd48..85e29bd 100644
--- a/android/rule_builder.go
+++ b/android/rule_builder.go
@@ -1157,11 +1157,15 @@
 
 // OutputDir adds the output directory to the command line. This is only available when used with RuleBuilder.Sbox,
 // and will be the temporary output directory managed by sbox, not the final one.
-func (c *RuleBuilderCommand) OutputDir() *RuleBuilderCommand {
+func (c *RuleBuilderCommand) OutputDir(subPathComponents ...string) *RuleBuilderCommand {
 	if !c.rule.sbox {
 		panic("OutputDir only valid with Sbox")
 	}
-	return c.Text(sboxOutDir)
+	path := sboxOutDir
+	if len(subPathComponents) > 0 {
+		path = filepath.Join(append([]string{sboxOutDir}, subPathComponents...)...)
+	}
+	return c.Text(path)
 }
 
 // DepFile adds the specified depfile path to the paths returned by RuleBuilder.DepFiles and adds it to the command
diff --git a/android/singleton.go b/android/singleton.go
index e0e552e..ccddeaf 100644
--- a/android/singleton.go
+++ b/android/singleton.go
@@ -250,8 +250,8 @@
 }
 
 func (s *singletonContextAdaptor) ModuleVariantsFromName(referer Module, name string) []Module {
-	// get qualified module name for visibility enforcement
-	qualified := createQualifiedModuleName(s.ModuleName(referer), s.ModuleDir(referer))
+	// get module reference for visibility enforcement
+	qualified := createVisibilityModuleReference(s.ModuleName(referer), s.ModuleDir(referer), s.ModuleType(referer))
 
 	modules := s.SingletonContext.ModuleVariantsFromName(referer, name)
 	result := make([]Module, 0, len(modules))
@@ -262,7 +262,7 @@
 			depDir := s.ModuleDir(module)
 			depQualified := qualifiedModuleName{depDir, depName}
 			// Targets are always visible to other targets in their own package.
-			if depQualified.pkg != qualified.pkg {
+			if depQualified.pkg != qualified.name.pkg {
 				rule := effectiveVisibilityRules(s.Config(), depQualified)
 				if !rule.matches(qualified) {
 					s.ModuleErrorf(referer, "module %q references %q which is not visible to this module\nYou may need to add %q to its visibility",
diff --git a/android/test_suites.go b/android/test_suites.go
index 9ded998..adcc15a 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -24,6 +24,7 @@
 
 type testSuiteFiles struct {
 	robolectric WritablePath
+	ravenwood   WritablePath
 }
 
 type TestSuiteModule interface {
@@ -47,12 +48,15 @@
 	})
 
 	t.robolectric = robolectricTestSuite(ctx, files["robolectric-tests"])
-
 	ctx.Phony("robolectric-tests", t.robolectric)
+
+	t.ravenwood = ravenwoodTestSuite(ctx, files["ravenwood-tests"])
+	ctx.Phony("ravenwood-tests", t.ravenwood)
 }
 
 func (t *testSuiteFiles) MakeVars(ctx MakeVarsContext) {
 	ctx.DistForGoal("robolectric-tests", t.robolectric)
+	ctx.DistForGoal("ravenwood-tests", t.ravenwood)
 }
 
 func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
@@ -74,3 +78,23 @@
 
 	return outputFile
 }
+
+func ravenwoodTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
+	var installedPaths InstallPaths
+	for _, module := range SortedKeys(files) {
+		installedPaths = append(installedPaths, files[module]...)
+	}
+	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases")
+
+	outputFile := PathForOutput(ctx, "packaging", "ravenwood-tests.zip")
+	rule := NewRuleBuilder(pctx, ctx)
+	rule.Command().BuiltTool("soong_zip").
+		FlagWithOutput("-o ", outputFile).
+		FlagWithArg("-P ", "host/testcases").
+		FlagWithArg("-C ", testCasesDir.String()).
+		FlagWithRspFileInputList("-r ", outputFile.ReplaceExtension(ctx, "rsp"), installedPaths.Paths()).
+		Flag("-sha256")
+	rule.Build("ravenwood_tests_zip", "ravenwood-tests.zip")
+
+	return outputFile
+}
diff --git a/android/visibility.go b/android/visibility.go
index 3130135..b387562 100644
--- a/android/visibility.go
+++ b/android/visibility.go
@@ -57,12 +57,29 @@
 
 var visibilityRuleRegexp = regexp.MustCompile(visibilityRulePattern)
 
+type visibilityModuleReference struct {
+	name              qualifiedModuleName
+	isPartitionModule bool
+}
+
+func createVisibilityModuleReference(name, dir, typ string) visibilityModuleReference {
+	isPartitionModule := false
+	switch typ {
+	case "android_filesystem", "android_system_image":
+		isPartitionModule = true
+	}
+	return visibilityModuleReference{
+		name:              createQualifiedModuleName(name, dir),
+		isPartitionModule: isPartitionModule,
+	}
+}
+
 // A visibility rule is associated with a module and determines which other modules it is visible
 // to, i.e. which other modules can depend on the rule's module.
 type visibilityRule interface {
 	// Check to see whether this rules matches m.
 	// Returns true if it does, false otherwise.
-	matches(m qualifiedModuleName) bool
+	matches(m visibilityModuleReference) bool
 
 	String() string
 }
@@ -108,8 +125,10 @@
 // ["//visibility:private"].
 type compositeRule []visibilityRule
 
+var _ visibilityRule = compositeRule{}
+
 // A compositeRule matches if and only if any of its rules matches.
-func (c compositeRule) matches(m qualifiedModuleName) bool {
+func (c compositeRule) matches(m visibilityModuleReference) bool {
 	for _, r := range c {
 		if r.matches(m) {
 			return true
@@ -135,8 +154,10 @@
 	pkg string
 }
 
-func (r packageRule) matches(m qualifiedModuleName) bool {
-	return m.pkg == r.pkg
+var _ visibilityRule = packageRule{}
+
+func (r packageRule) matches(m visibilityModuleReference) bool {
+	return m.name.pkg == r.pkg
 }
 
 func (r packageRule) String() string {
@@ -149,8 +170,10 @@
 	pkgPrefix string
 }
 
-func (r subpackagesRule) matches(m qualifiedModuleName) bool {
-	return isAncestor(r.pkgPrefix, m.pkg)
+var _ visibilityRule = subpackagesRule{}
+
+func (r subpackagesRule) matches(m visibilityModuleReference) bool {
+	return isAncestor(r.pkgPrefix, m.name.pkg)
 }
 
 func isAncestor(p1 string, p2 string) bool {
@@ -168,7 +191,9 @@
 // visibilityRule for //visibility:public
 type publicRule struct{}
 
-func (r publicRule) matches(_ qualifiedModuleName) bool {
+var _ visibilityRule = publicRule{}
+
+func (r publicRule) matches(_ visibilityModuleReference) bool {
 	return true
 }
 
@@ -179,7 +204,9 @@
 // visibilityRule for //visibility:private
 type privateRule struct{}
 
-func (r privateRule) matches(_ qualifiedModuleName) bool {
+var _ visibilityRule = privateRule{}
+
+func (r privateRule) matches(_ visibilityModuleReference) bool {
 	return false
 }
 
@@ -187,6 +214,19 @@
 	return "//visibility:private"
 }
 
+// visibilityRule for //visibility:any_partition
+type anyPartitionRule struct{}
+
+var _ visibilityRule = anyPartitionRule{}
+
+func (r anyPartitionRule) matches(m visibilityModuleReference) bool {
+	return m.isPartitionModule
+}
+
+func (r anyPartitionRule) String() string {
+	return "//visibility:any_partition"
+}
+
 var visibilityRuleMap = NewOnceKey("visibilityRuleMap")
 
 // The map from qualifiedModuleName to visibilityRule.
@@ -237,13 +277,10 @@
 
 // Checks the per-module visibility rule lists before defaults expansion.
 func visibilityRuleChecker(ctx BottomUpMutatorContext) {
-	qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
-	if m, ok := ctx.Module().(Module); ok {
-		visibilityProperties := m.visibilityProperties()
-		for _, p := range visibilityProperties {
-			if visibility := p.getStrings(); visibility != nil {
-				checkRules(ctx, qualified.pkg, p.getName(), visibility)
-			}
+	visibilityProperties := ctx.Module().visibilityProperties()
+	for _, p := range visibilityProperties {
+		if visibility := p.getStrings(); visibility != nil {
+			checkRules(ctx, ctx.ModuleDir(), p.getName(), visibility)
 		}
 	}
 }
@@ -266,7 +303,7 @@
 
 		if pkg == "visibility" {
 			switch name {
-			case "private", "public":
+			case "private", "public", "any_partition":
 			case "legacy_public":
 				ctx.PropertyErrorf(property, "//visibility:legacy_public must not be used")
 				continue
@@ -305,10 +342,7 @@
 //
 // See ../README.md#Visibility for information on the format of the visibility rules.
 func visibilityRuleGatherer(ctx BottomUpMutatorContext) {
-	m, ok := ctx.Module().(Module)
-	if !ok {
-		return
-	}
+	m := ctx.Module()
 
 	qualifiedModuleId := m.qualifiedModuleId(ctx)
 	currentPkg := qualifiedModuleId.pkg
@@ -355,6 +389,8 @@
 				hasNonPrivateRule = false
 				// This does not actually create a rule so continue onto the next rule.
 				continue
+			case "any_partition":
+				r = anyPartitionRule{}
 			}
 		} else {
 			switch name {
@@ -395,10 +431,7 @@
 
 func isAllowedFromOutsideVendor(pkg string, name string) bool {
 	if pkg == "vendor" {
-		if name == "__subpackages__" {
-			return true
-		}
-		return false
+		return name == "__subpackages__"
 	}
 
 	return !isAncestor("vendor", pkg)
@@ -434,11 +467,7 @@
 }
 
 func visibilityRuleEnforcer(ctx TopDownMutatorContext) {
-	if _, ok := ctx.Module().(Module); !ok {
-		return
-	}
-
-	qualified := createQualifiedModuleName(ctx.ModuleName(), ctx.ModuleDir())
+	qualified := createVisibilityModuleReference(ctx.ModuleName(), ctx.ModuleDir(), ctx.ModuleType())
 
 	// Visit all the dependencies making sure that this module has access to them all.
 	ctx.VisitDirectDeps(func(dep Module) {
@@ -453,7 +482,7 @@
 		depQualified := qualifiedModuleName{depDir, depName}
 
 		// Targets are always visible to other targets in their own package.
-		if depQualified.pkg == qualified.pkg {
+		if depQualified.pkg == qualified.name.pkg {
 			return
 		}
 
@@ -478,7 +507,7 @@
 	if ok {
 		rule = value.(compositeRule)
 	} else {
-		rule = packageDefaultVisibility(config, qualified)
+		rule = packageDefaultVisibility(moduleToVisibilityRule, qualified)
 	}
 
 	// If no rule is specified then return the default visibility rule to avoid
@@ -494,8 +523,7 @@
 	return qualified
 }
 
-func packageDefaultVisibility(config Config, moduleId qualifiedModuleName) compositeRule {
-	moduleToVisibilityRule := moduleToVisibilityRuleMap(config)
+func packageDefaultVisibility(moduleToVisibilityRule *sync.Map, moduleId qualifiedModuleName) compositeRule {
 	packageQualifiedId := moduleId.getContainingPackageId()
 	for {
 		value, ok := moduleToVisibilityRule.Load(packageQualifiedId)
@@ -574,10 +602,12 @@
 
 	rule := effectiveVisibilityRules(ctx.Config(), qualified)
 
+	currentModule := createVisibilityModuleReference(moduleName, dir, ctx.OtherModuleType(module))
+
 	// Modules are implicitly visible to other modules in the same package,
 	// without checking the visibility rules. Here we need to add that visibility
 	// explicitly.
-	if !rule.matches(qualified) {
+	if !rule.matches(currentModule) {
 		if len(rule) == 1 {
 			if _, ok := rule[0].(privateRule); ok {
 				// If the rule is //visibility:private we can't append another
diff --git a/android/visibility_test.go b/android/visibility_test.go
index a66f0b6..d4add7d 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1904,6 +1904,38 @@
 				}`),
 		},
 	},
+	{
+		name: "any_partition visibility works",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				android_filesystem {
+					name: "foo",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				package(default_visibility=["//visibility:private"])
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_partition"],
+				}`),
+		},
+	},
+	{
+		name: "any_partition visibility doesn't work for non-partitions",
+		fs: MockFS{
+			"top/Android.bp": []byte(`
+				mock_library {
+					name: "foo",
+					deps: ["bar"],
+				}`),
+			"top/nested/Android.bp": []byte(`
+				mock_library {
+					name: "bar",
+					visibility: ["//visibility:any_partition"],
+				}`),
+		},
+		expectedErrors: []string{`module "foo" variant "android_common": depends on //top/nested:bar which is not visible to this module`},
+	},
 }
 
 func TestVisibility(t *testing.T) {
@@ -1925,6 +1957,8 @@
 					ctx.RegisterModuleType("mock_library", newMockLibraryModule)
 					ctx.RegisterModuleType("mock_parent", newMockParentFactory)
 					ctx.RegisterModuleType("mock_defaults", defaultsFactory)
+					// For testing //visibility:any_partition. The module type doesn't matter, just that it's registered under the name "android_filesystem"
+					ctx.RegisterModuleType("android_filesystem", newMockLibraryModule)
 				}),
 				prepareForTestWithFakePrebuiltModules,
 				// Add additional files to the mock filesystem
diff --git a/apex/builder.go b/apex/builder.go
index 3078863..40ccd2c 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -910,7 +910,7 @@
 	var validations android.Paths
 	validations = append(validations, runApexLinkerconfigValidation(ctx, unsignedOutputFile.OutputPath, imageDir.OutputPath))
 	// TODO(b/279688635) deapexer supports [ext4]
-	if suffix == imageApexSuffix && ext4 == a.payloadFsType {
+	if !a.testApex && suffix == imageApexSuffix && ext4 == a.payloadFsType {
 		validations = append(validations, runApexSepolicyTests(ctx, unsignedOutputFile.OutputPath))
 	}
 	if !a.testApex && len(a.properties.Unwanted_transitive_deps) > 0 {
diff --git a/cc/afdo.go b/cc/afdo.go
index 79fbae1..6cc1746 100644
--- a/cc/afdo.go
+++ b/cc/afdo.go
@@ -68,6 +68,10 @@
 }
 
 func (afdo *afdo) flags(ctx ModuleContext, flags Flags) Flags {
+	if ctx.Host() {
+		return flags
+	}
+
 	if afdo.Properties.Afdo {
 		// We use `-funique-internal-linkage-names` to associate profiles to the right internal
 		// functions. This option should be used before generating a profile. Because a profile
@@ -147,6 +151,10 @@
 
 // Propagate afdo requirements down from binaries and shared libraries
 func afdoDepsMutator(mctx android.TopDownMutatorContext) {
+	if mctx.Host() {
+		return
+	}
+
 	if m, ok := mctx.Module().(*Module); ok && m.afdo.afdoEnabled() {
 		path := m.afdo.Properties.FdoProfilePath
 		mctx.WalkDeps(func(dep android.Module, parent android.Module) bool {
@@ -181,6 +189,10 @@
 
 // Create afdo variants for modules that need them
 func afdoMutator(mctx android.BottomUpMutatorContext) {
+	if mctx.Host() {
+		return
+	}
+
 	if m, ok := mctx.Module().(*Module); ok && m.afdo != nil {
 		if !m.static() && m.afdo.Properties.Afdo {
 			mctx.SetDependencyVariation(encodeTarget(m.Name()))
diff --git a/cc/afdo_test.go b/cc/afdo_test.go
index b250ad1..3eab039 100644
--- a/cc/afdo_test.go
+++ b/cc/afdo_test.go
@@ -42,19 +42,25 @@
 	bp := `
 	cc_library_shared {
 		name: "libTest",
+		host_supported: true,
 		srcs: ["test.c"],
 		static_libs: ["libFoo"],
 		afdo: true,
+		lto: {
+			thin: true,
+		},
 	}
 
 	cc_library_static {
 		name: "libFoo",
+		host_supported: true,
 		srcs: ["foo.c"],
 		static_libs: ["libBar"],
 	}
 
 	cc_library_static {
 		name: "libBar",
+		host_supported: true,
 		srcs: ["bar.c"],
 	}
 	`
@@ -72,13 +78,20 @@
 			"afdo_profiles_package/Android.bp": []byte(`
 				fdo_profile {
 					name: "libTest_afdo",
-					profile: "libTest.afdo",
+					arch: {
+						arm64: {
+							profile: "libTest.afdo",
+						},
+					},
 				}
 			`),
 		}.AddToFixture(),
 	).RunTestWithBp(t, bp)
 
-	expectedCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+	profileSampleCFlag := "-fprofile-sample-use=afdo_profiles_package/libTest.afdo"
+	uniqueInternalLinkageNamesCFlag := "-funique-internal-linkage-names"
+	afdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=40"
+	noAfdoLtoLdFlag := "-Wl,-plugin-opt,-import-instr-limit=5"
 
 	libTest := result.ModuleForTests("libTest", "android_arm64_armv8-a_shared")
 	libFooAfdoVariant := result.ModuleForTests("libFoo", "android_arm64_armv8-a_static_afdo-libTest")
@@ -86,18 +99,32 @@
 
 	// Check cFlags of afdo-enabled module and the afdo-variant of its static deps
 	cFlags := libTest.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	ldFlags := libTest.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, afdoLtoLdFlag) {
+		t.Errorf("Expected 'libTest' to enable afdo, but did not find %q in ldflags %q", afdoLtoLdFlag, ldFlags)
 	}
 
 	cFlags = libFooAfdoVariant.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libFooAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	cFlags = libBarAfdoVariant.Rule("cc").Args["cFlags"]
-	if !strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", expectedCFlag, cFlags)
+	if !strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo profile, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libBarAfdoVariant' to enable afdo, but did not find %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	// Check dependency edge from afdo-enabled module to static deps
@@ -114,12 +141,18 @@
 	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static")
 
 	cFlags = libFoo.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libFoo' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 	cFlags = libBar.Rule("cc").Args["cFlags"]
-	if strings.Contains(cFlags, expectedCFlag) {
-		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", expectedCFlag, cFlags)
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected 'libBar' to not enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
 	}
 
 	// Check dependency edges of static deps
@@ -130,6 +163,102 @@
 	if !hasDirectDep(result, libFoo.Module(), libBar.Module()) {
 		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
+
+	// Verify that the arm variant does not have FDO since the fdo_profile module only has a profile for arm64
+	libTest32 := result.ModuleForTests("libTest", "android_arm_armv7-a-neon_shared")
+	libFooAfdoVariant32 := result.ModuleForTests("libFoo", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin")
+	libBarAfdoVariant32 := result.ModuleForTests("libBar", "android_arm_armv7-a-neon_static_afdo-libTest_lto-thin")
+
+	cFlags = libTest32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libTest' not to enable afdo, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	// TODO(b/324141705): when the fdo_profile module doesn't provide a source file the dependencies don't get
+	//  -funique-internal-linkage-names but the module does.
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libTest' to enable -funique-internal-linkage-names but did not find %q in cflags %q",
+			uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	ldFlags = libTest32.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, noAfdoLtoLdFlag) {
+		t.Errorf("Expected arm32 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags)
+	}
+	if strings.Contains(ldFlags, afdoLtoLdFlag) {
+		t.Errorf("Expected arm32 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags)
+	}
+
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTest32.Module(), libFooAfdoVariant32.Module()) {
+		t.Errorf("arm32 libTest missing dependency on afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooAfdoVariant32.Module(), libBarAfdoVariant32.Module()) {
+		t.Errorf("arm32 libTest missing dependency on afdo variant of libBar")
+	}
+
+	cFlags = libFooAfdoVariant32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libFoo' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	cFlags = libBarAfdoVariant32.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected arm32 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if !strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected arm32 'libBar' to enable afdo, but did not find %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	// Verify that the host variants don't enable afdo
+	libTestHost := result.ModuleForTests("libTest", result.Config.BuildOSTarget.String()+"_shared")
+	libFooHost := result.ModuleForTests("libFoo", result.Config.BuildOSTarget.String()+"_static_lto-thin")
+	libBarHost := result.ModuleForTests("libBar", result.Config.BuildOSTarget.String()+"_static_lto-thin")
+
+	cFlags = libTestHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo profile, but found %q in cflags %q", profileSampleCFlag, cFlags)
+	}
+
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo but found %q in cflags %q",
+			uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+
+	ldFlags = libTestHost.Rule("ld").Args["ldFlags"]
+	if !strings.Contains(ldFlags, noAfdoLtoLdFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo, but did not find %q in ldflags %q", noAfdoLtoLdFlag, ldFlags)
+	}
+	if strings.Contains(ldFlags, afdoLtoLdFlag) {
+		t.Errorf("Expected host 'libTest' to not enable afdo, but found %q in ldflags %q", afdoLtoLdFlag, ldFlags)
+	}
+
+	// Check dependency edge from afdo-enabled module to static deps
+	if !hasDirectDep(result, libTestHost.Module(), libFooHost.Module()) {
+		t.Errorf("host libTest missing dependency on non-afdo variant of libFoo")
+	}
+
+	if !hasDirectDep(result, libFooHost.Module(), libBarHost.Module()) {
+		t.Errorf("host libTest missing dependency on non-afdo variant of libBar")
+	}
+
+	cFlags = libFooHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libFoo' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libFoo' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	cFlags = libBarHost.Rule("cc").Args["cFlags"]
+	if strings.Contains(cFlags, profileSampleCFlag) {
+		t.Errorf("Expected host 'libBar' to not enable afdo profile, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
+	if strings.Contains(cFlags, uniqueInternalLinkageNamesCFlag) {
+		t.Errorf("Expected host 'libBar' to not enable afdo, but found %q in cflags %q", uniqueInternalLinkageNamesCFlag, cFlags)
+	}
 }
 
 func TestAfdoEnabledOnStaticDepNoAfdo(t *testing.T) {
@@ -174,11 +303,11 @@
 	libBar := result.ModuleForTests("libBar", "android_arm64_armv8-a_static").Module()
 
 	if !hasDirectDep(result, libTest, libFoo.Module()) {
-		t.Errorf("libTest missing dependency on afdo variant of libFoo")
+		t.Errorf("libTest missing dependency on non-afdo variant of libFoo")
 	}
 
 	if !hasDirectDep(result, libFoo.Module(), libBar) {
-		t.Errorf("libFoo missing dependency on afdo variant of libBar")
+		t.Errorf("libFoo missing dependency on non-afdo variant of libBar")
 	}
 
 	fooVariants := result.ModuleVariantsForTests("foo")
diff --git a/cc/config/global.go b/cc/config/global.go
index c562614..613641f 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -254,7 +254,7 @@
 		"-Wno-pointer-to-int-cast",
 		"-Werror=fortify-source",
 		// http://b/315246135 temporarily disabled
-		"-Wno-error=unused-variable",
+		"-Wno-unused-variable",
 		// http://b/315250603 temporarily disabled
 		"-Wno-error=format",
 		// Disabled because it produces many false positives. http://b/323050926
@@ -302,6 +302,8 @@
 		// until then because it causes warnings in the _callers_, not the
 		// project itself.
 		"-Wno-deprecated-dynamic-exception-spec",
+		// http://b/324323434
+		"-Wno-ambiguous-reversed-operator",
 	}
 
 	noOverride64GlobalCflags = []string{}
diff --git a/cc/config/x86_windows_host.go b/cc/config/x86_windows_host.go
index 561c500..1e61b01 100644
--- a/cc/config/x86_windows_host.go
+++ b/cc/config/x86_windows_host.go
@@ -27,9 +27,8 @@
 		"-DWIN32_LEAN_AND_MEAN",
 		"-Wno-unused-parameter",
 
-		// Workaround differences in inttypes.h between host and target.
-		//See bug 12708004.
-		"-D__STDC_FORMAT_MACROS",
+		// Workaround differences in <stdint.h> between host and target.
+		// Context: http://b/12708004
 		"-D__STDC_CONSTANT_MACROS",
 
 		// Use C99-compliant printf functions (%zd).
diff --git a/filesystem/filesystem.go b/filesystem/filesystem.go
index 2f6476c..6612a6f 100644
--- a/filesystem/filesystem.go
+++ b/filesystem/filesystem.go
@@ -50,8 +50,8 @@
 	// Function that builds extra files under the root directory and returns the files
 	buildExtraFiles func(ctx android.ModuleContext, root android.OutputPath) android.OutputPaths
 
-	// Function that filters PackagingSpecs returned by PackagingBase.GatherPackagingSpecs()
-	filterPackagingSpecs func(specs map[string]android.PackagingSpec)
+	// Function that filters PackagingSpec in PackagingBase.GatherPackagingSpecs()
+	filterPackagingSpec func(spec android.PackagingSpec) bool
 
 	output     android.OutputPath
 	installDir android.InstallPath
@@ -493,10 +493,7 @@
 // Note that "apex" module installs its contents to "apex"(fake partition) as well
 // for symbol lookup by imitating "activated" paths.
 func (f *filesystem) gatherFilteredPackagingSpecs(ctx android.ModuleContext) map[string]android.PackagingSpec {
-	specs := f.PackagingBase.GatherPackagingSpecs(ctx)
-	if f.filterPackagingSpecs != nil {
-		f.filterPackagingSpecs(specs)
-	}
+	specs := f.PackagingBase.GatherPackagingSpecsWithFilter(ctx, f.filterPackagingSpec)
 	return specs
 }
 
diff --git a/filesystem/system_image.go b/filesystem/system_image.go
index 75abf70..34f4ffb 100644
--- a/filesystem/system_image.go
+++ b/filesystem/system_image.go
@@ -37,7 +37,7 @@
 	module := &systemImage{}
 	module.AddProperties(&module.properties)
 	module.filesystem.buildExtraFiles = module.buildExtraFiles
-	module.filesystem.filterPackagingSpecs = module.filterPackagingSpecs
+	module.filesystem.filterPackagingSpec = module.filterPackagingSpec
 	initFilesystemModule(&module.filesystem)
 	return module
 }
@@ -73,10 +73,6 @@
 // Filter the result of GatherPackagingSpecs to discard items targeting outside "system" partition.
 // Note that "apex" module installs its contents to "apex"(fake partition) as well
 // for symbol lookup by imitating "activated" paths.
-func (s *systemImage) filterPackagingSpecs(specs map[string]android.PackagingSpec) {
-	for k, ps := range specs {
-		if ps.Partition() != "system" {
-			delete(specs, k)
-		}
-	}
+func (s *systemImage) filterPackagingSpec(ps android.PackagingSpec) bool {
+	return ps.Partition() == "system"
 }
diff --git a/java/Android.bp b/java/Android.bp
index 2585cd2..54b36ab 100644
--- a/java/Android.bp
+++ b/java/Android.bp
@@ -67,6 +67,7 @@
         "plugin.go",
         "prebuilt_apis.go",
         "proto.go",
+        "ravenwood.go",
         "robolectric.go",
         "rro.go",
         "sdk.go",
@@ -107,6 +108,7 @@
         "plugin_test.go",
         "prebuilt_apis_test.go",
         "proto_test.go",
+        "ravenwood_test.go",
         "rro_test.go",
         "sdk_library_test.go",
         "sdk_test.go",
diff --git a/java/base.go b/java/base.go
index 284ec99..4e2366f 100644
--- a/java/base.go
+++ b/java/base.go
@@ -2441,6 +2441,9 @@
 	// Gather repackage information from deps
 	// If the dep jas a JarJarProvider, it is used.  Otherwise, any BaseJarJarProvider is used.
 	ctx.VisitDirectDepsIgnoreBlueprint(func(m android.Module) {
+		if ctx.OtherModuleDependencyTag(m) == proguardRaiseTag {
+			return
+		}
 		merge := func(theirs *JarJarProviderData) {
 			for orig, renamed := range theirs.Rename {
 				if result == nil {
diff --git a/java/builder.go b/java/builder.go
index 085e7a1..74a05f2 100644
--- a/java/builder.go
+++ b/java/builder.go
@@ -277,7 +277,7 @@
 
 	gatherReleasedFlaggedApisRule = pctx.AndroidStaticRule("gatherReleasedFlaggedApisRule",
 		blueprint.RuleParams{
-			Command: `${aconfig} dump-cache --format='{fully_qualified_name}={state:bool}' ` +
+			Command: `${aconfig} dump-cache --dedup --format='{fully_qualified_name}={state:bool}' ` +
 				`--out ${out} ` +
 				`${flags_path} ` +
 				`${filter_args} `,
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 56ae427..51503f2 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -744,8 +744,14 @@
 		filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
 
 	case Exportable:
-		filterArgs = "--filter='state:ENABLED+permission:READ_ONLY'"
-
+		// When the build flag RELEASE_EXPORT_RUNTIME_APIS is set to true, apis marked with
+		// the flagged apis that have read_write permissions are exposed on top of the enabled
+		// and read_only apis. This is to support local override of flag values at runtime.
+		if ctx.Config().ReleaseExportRuntimeApis() {
+			filterArgs = "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
+		} else {
+			filterArgs = "--filter='state:ENABLED+permission:READ_ONLY'"
+		}
 	}
 
 	ctx.Build(pctx, android.BuildParams{
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 52cd1c5..caa8345 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -412,3 +412,48 @@
 	android.AssertStringDoesContain(t, "foo generates exportable stubs jar",
 		strings.Join(m.AllOutputs(), ""), "exportable/foo-stubs.srcjar")
 }
+
+func TestReleaseExportRuntimeApis(t *testing.T) {
+	result := android.GroupFixturePreparers(
+		prepareForJavaTest,
+		android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+			variables.BuildFlags = map[string]string{
+				"RELEASE_HIDDEN_API_EXPORTABLE_STUBS": "true",
+				"RELEASE_EXPORT_RUNTIME_APIS":         "true",
+			}
+		}),
+		android.FixtureMergeMockFs(map[string][]byte{
+			"a/A.java":      nil,
+			"a/current.txt": nil,
+			"a/removed.txt": nil,
+		}),
+	).RunTestWithBp(t, `
+	aconfig_declarations {
+		name: "bar",
+		package: "com.example.package",
+		srcs: [
+			"bar.aconfig",
+		],
+	}
+	droidstubs {
+		name: "foo",
+		srcs: ["a/A.java"],
+		api_surface: "public",
+		check_api: {
+			current: {
+				api_file: "a/current.txt",
+				removed_api_file: "a/removed.txt",
+			}
+		},
+		aconfig_declarations: [
+			"bar",
+		],
+	}
+	`)
+
+	m := result.ModuleForTests("foo", "android_common")
+
+	rule := m.Output("released-flagged-apis-exportable.txt")
+	exposeWritableApisFilter := "--filter='state:ENABLED+permission:READ_ONLY' --filter='permission:READ_WRITE'"
+	android.AssertStringEquals(t, "Filter argument expected to contain READ_WRITE permissions", exposeWritableApisFilter, rule.Args["filter_args"])
+}
diff --git a/java/ravenwood.go b/java/ravenwood.go
new file mode 100644
index 0000000..dcb5c8b
--- /dev/null
+++ b/java/ravenwood.go
@@ -0,0 +1,228 @@
+// Copyright 2023 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//	http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+package java
+
+import (
+	"android/soong/android"
+	"android/soong/tradefed"
+
+	"github.com/google/blueprint/proptools"
+)
+
+func init() {
+	RegisterRavenwoodBuildComponents(android.InitRegistrationContext)
+}
+
+func RegisterRavenwoodBuildComponents(ctx android.RegistrationContext) {
+	ctx.RegisterModuleType("android_ravenwood_test", ravenwoodTestFactory)
+	ctx.RegisterModuleType("android_ravenwood_libgroup", ravenwoodLibgroupFactory)
+}
+
+var ravenwoodTag = dependencyTag{name: "ravenwood"}
+var ravenwoodJniTag = dependencyTag{name: "ravenwood-jni"}
+
+const ravenwoodUtilsName = "ravenwood-utils"
+const ravenwoodRuntimeName = "ravenwood-runtime"
+
+func getLibPath(archType android.ArchType) string {
+	if archType.Multilib == "lib64" {
+		return "lib64"
+	}
+	return "lib"
+}
+
+type ravenwoodTestProperties struct {
+	Jni_libs []string
+}
+
+type ravenwoodTest struct {
+	Library
+
+	ravenwoodTestProperties ravenwoodTestProperties
+
+	testProperties testProperties
+	testConfig     android.Path
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
+}
+
+func ravenwoodTestFactory() android.Module {
+	module := &ravenwoodTest{}
+
+	module.addHostAndDeviceProperties()
+	module.AddProperties(&module.testProperties, &module.ravenwoodTestProperties)
+
+	module.Module.dexpreopter.isTest = true
+	module.Module.linter.properties.Lint.Test = proptools.BoolPtr(true)
+
+	module.testProperties.Test_suites = []string{
+		"general-tests",
+		"ravenwood-tests",
+	}
+	module.testProperties.Test_options.Unit_test = proptools.BoolPtr(false)
+
+	InitJavaModule(module, android.DeviceSupported)
+	android.InitDefaultableModule(module)
+
+	return module
+}
+
+func (r *ravenwoodTest) InstallInTestcases() bool { return true }
+func (r *ravenwoodTest) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &r.forceOSType, &r.forceArchType
+}
+func (r *ravenwoodTest) TestSuites() []string {
+	return r.testProperties.Test_suites
+}
+
+func (r *ravenwoodTest) DepsMutator(ctx android.BottomUpMutatorContext) {
+	r.Library.DepsMutator(ctx)
+
+	// Generically depend on the runtime so that it's installed together with us
+	ctx.AddVariationDependencies(nil, ravenwoodTag, ravenwoodRuntimeName)
+
+	// Directly depend on any utils so that we link against them
+	utils := ctx.AddVariationDependencies(nil, ravenwoodTag, ravenwoodUtilsName)[0]
+	if utils != nil {
+		for _, lib := range utils.(*ravenwoodLibgroup).ravenwoodLibgroupProperties.Libs {
+			ctx.AddVariationDependencies(nil, libTag, lib)
+		}
+	}
+
+	// Add jni libs
+	for _, lib := range r.ravenwoodTestProperties.Jni_libs {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), ravenwoodJniTag, lib)
+	}
+}
+
+func (r *ravenwoodTest) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
+	r.testConfig = tradefed.AutoGenTestConfig(ctx, tradefed.AutoGenTestConfigOptions{
+		TestConfigProp:         r.testProperties.Test_config,
+		TestConfigTemplateProp: r.testProperties.Test_config_template,
+		TestSuites:             r.testProperties.Test_suites,
+		AutoGenConfig:          r.testProperties.Auto_gen_config,
+		DeviceTemplate:         "${RavenwoodTestConfigTemplate}",
+		HostTemplate:           "${RavenwoodTestConfigTemplate}",
+	})
+
+	r.Library.GenerateAndroidBuildActions(ctx)
+
+	// Start by depending on all files installed by dependancies
+	var installDeps android.InstallPaths
+	for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodTag) {
+		for _, installFile := range dep.FilesToInstall() {
+			installDeps = append(installDeps, installFile)
+		}
+	}
+
+	// Also depend on our config
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	installConfig := ctx.InstallFile(installPath, ctx.ModuleName()+".config", r.testConfig)
+	installDeps = append(installDeps, installConfig)
+
+	// Depend on the JNI libraries.
+	soInstallPath := installPath.Join(ctx, getLibPath(r.forceArchType))
+	for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodJniTag) {
+		file := android.OutputFileForModule(ctx, dep, "")
+		installJni := ctx.InstallFile(soInstallPath, file.Base(), file)
+		installDeps = append(installDeps, installJni)
+	}
+
+	// Install our JAR with all dependencies
+	ctx.InstallFile(installPath, ctx.ModuleName()+".jar", r.outputFile, installDeps...)
+}
+
+func (r *ravenwoodTest) AndroidMkEntries() []android.AndroidMkEntries {
+	entriesList := r.Library.AndroidMkEntries()
+	entries := &entriesList[0]
+	entries.ExtraEntries = append(entries.ExtraEntries,
+		func(ctx android.AndroidMkExtraEntriesContext, entries *android.AndroidMkEntries) {
+			entries.SetBool("LOCAL_UNINSTALLABLE_MODULE", true)
+			entries.AddStrings("LOCAL_COMPATIBILITY_SUITE",
+				"general-tests", "ravenwood-tests")
+			if r.testConfig != nil {
+				entries.SetPath("LOCAL_FULL_TEST_CONFIG", r.testConfig)
+			}
+		})
+	return entriesList
+}
+
+type ravenwoodLibgroupProperties struct {
+	Libs []string
+
+	Jni_libs []string
+}
+
+type ravenwoodLibgroup struct {
+	android.ModuleBase
+
+	ravenwoodLibgroupProperties ravenwoodLibgroupProperties
+
+	forceOSType   android.OsType
+	forceArchType android.ArchType
+}
+
+func ravenwoodLibgroupFactory() android.Module {
+	module := &ravenwoodLibgroup{}
+	module.AddProperties(&module.ravenwoodLibgroupProperties)
+
+	android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
+	return module
+}
+
+func (r *ravenwoodLibgroup) InstallInTestcases() bool { return true }
+func (r *ravenwoodLibgroup) InstallForceOS() (*android.OsType, *android.ArchType) {
+	return &r.forceOSType, &r.forceArchType
+}
+func (r *ravenwoodLibgroup) TestSuites() []string {
+	return []string{
+		"general-tests",
+		"ravenwood-tests",
+	}
+}
+
+func (r *ravenwoodLibgroup) DepsMutator(ctx android.BottomUpMutatorContext) {
+	// Always depends on our underlying libs
+	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
+		ctx.AddVariationDependencies(nil, ravenwoodTag, lib)
+	}
+	for _, lib := range r.ravenwoodLibgroupProperties.Jni_libs {
+		ctx.AddVariationDependencies(ctx.Config().BuildOSTarget.Variations(), ravenwoodJniTag, lib)
+	}
+}
+
+func (r *ravenwoodLibgroup) GenerateAndroidBuildActions(ctx android.ModuleContext) {
+	r.forceOSType = ctx.Config().BuildOS
+	r.forceArchType = ctx.Config().BuildArch
+
+	// Install our runtime into expected location for packaging
+	installPath := android.PathForModuleInstall(ctx, r.BaseModuleName())
+	for _, lib := range r.ravenwoodLibgroupProperties.Libs {
+		libModule := ctx.GetDirectDepWithTag(lib, ravenwoodTag)
+		libJar := android.OutputFileForModule(ctx, libModule, "")
+		ctx.InstallFile(installPath, lib+".jar", libJar)
+	}
+	soInstallPath := android.PathForModuleInstall(ctx, r.BaseModuleName()).Join(ctx, getLibPath(r.forceArchType))
+	for _, dep := range ctx.GetDirectDepsWithTag(ravenwoodJniTag) {
+		file := android.OutputFileForModule(ctx, dep, "")
+		ctx.InstallFile(soInstallPath, file.Base(), file)
+	}
+
+	// Normal build should perform install steps
+	ctx.Phony(r.BaseModuleName(), android.PathForPhony(ctx, r.BaseModuleName()+"-install"))
+}
diff --git a/java/ravenwood_test.go b/java/ravenwood_test.go
new file mode 100644
index 0000000..a71391c
--- /dev/null
+++ b/java/ravenwood_test.go
@@ -0,0 +1,154 @@
+// Copyright 2022 Google Inc. All rights reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package java
+
+import (
+	"runtime"
+	"testing"
+
+	"android/soong/android"
+)
+
+var prepareRavenwoodRuntime = android.GroupFixturePreparers(
+	android.FixtureRegisterWithContext(func(ctx android.RegistrationContext) {
+		RegisterRavenwoodBuildComponents(ctx)
+	}),
+	android.FixtureAddTextFile("ravenwood/Android.bp", `
+		cc_library_shared {
+			name: "ravenwood-runtime-jni",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+		}
+		cc_library_shared {
+			name: "ravenwood-runtime-jni2",
+			host_supported: true,
+			srcs: ["jni.cpp"],
+			stem: "libred",
+		}
+		java_library_static {
+			name: "framework-minus-apex.ravenwood",
+			srcs: ["Framework.java"],
+		}
+		java_library_static {
+			name: "framework-services.ravenwood",
+			srcs: ["Services.java"],
+		}
+		java_library_static {
+			name: "framework-rules.ravenwood",
+			srcs: ["Rules.java"],
+		}
+		android_ravenwood_libgroup {
+			name: "ravenwood-runtime",
+			libs: [
+				"framework-minus-apex.ravenwood",
+				"framework-services.ravenwood",
+			],
+			jni_libs: ["ravenwood-runtime-jni", "ravenwood-runtime-jni2"],
+		}
+		android_ravenwood_libgroup {
+			name: "ravenwood-utils",
+			libs: [
+				"framework-rules.ravenwood",
+			],
+		}
+	`),
+)
+
+var installPathPrefix = "out/soong/host/linux-x86/testcases"
+
+func TestRavenwoodRuntime(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	ctx := android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		prepareRavenwoodRuntime,
+	).RunTest(t)
+
+	// Verify that our runtime depends on underlying libs
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "framework-minus-apex.ravenwood")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "framework-services.ravenwood")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-runtime", "android_common", "ravenwood-runtime-jni")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-utils", "android_common", "framework-rules.ravenwood")
+
+	// Verify that we've emitted artifacts in expected location
+	runtime := ctx.ModuleForTests("ravenwood-runtime", "android_common")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-minus-apex.ravenwood.jar")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/framework-services.ravenwood.jar")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/ravenwood-runtime-jni.so")
+	runtime.Output(installPathPrefix + "/ravenwood-runtime/lib64/libred.so")
+	utils := ctx.ModuleForTests("ravenwood-utils", "android_common")
+	utils.Output(installPathPrefix + "/ravenwood-utils/framework-rules.ravenwood.jar")
+}
+
+func TestRavenwoodTest(t *testing.T) {
+	if runtime.GOOS != "linux" {
+		t.Skip("requires linux")
+	}
+
+	ctx := android.GroupFixturePreparers(
+		PrepareForIntegrationTestWithJava,
+		prepareRavenwoodRuntime,
+	).RunTestWithBp(t, `
+	cc_library_shared {
+		name: "jni-lib",
+		host_supported: true,
+		srcs: ["jni.cpp"],
+	}
+	cc_library_shared {
+		name: "jni-lib2",
+		host_supported: true,
+		srcs: ["jni.cpp"],
+		stem: "libblue",
+	}
+	android_ravenwood_test {
+			name: "ravenwood-test",
+			srcs: ["Test.java"],
+			jni_libs: ["jni-lib", "jni-lib2"],
+			sdk_version: "test_current",
+		}
+	`)
+
+	// Verify that our test depends on underlying libs
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "ravenwood-buildtime")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "ravenwood-utils")
+	CheckModuleHasDependency(t, ctx.TestContext, "ravenwood-test", "android_common", "jni-lib")
+
+	module := ctx.ModuleForTests("ravenwood-test", "android_common")
+	classpath := module.Rule("javac").Args["classpath"]
+
+	// Verify that we're linking against test_current
+	android.AssertStringDoesContain(t, "classpath", classpath, "android_test_stubs_current.jar")
+	// Verify that we're linking against utils
+	android.AssertStringDoesContain(t, "classpath", classpath, "framework-rules.ravenwood.jar")
+	// Verify that we're *NOT* linking against runtime
+	android.AssertStringDoesNotContain(t, "classpath", classpath, "framework-minus-apex.ravenwood.jar")
+	android.AssertStringDoesNotContain(t, "classpath", classpath, "framework-services.ravenwood.jar")
+
+	// Verify that we've emitted test artifacts in expected location
+	outputJar := module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.jar")
+	module.Output(installPathPrefix + "/ravenwood-test/ravenwood-test.config")
+	module.Output(installPathPrefix + "/ravenwood-test/lib64/jni-lib.so")
+	module.Output(installPathPrefix + "/ravenwood-test/lib64/libblue.so")
+
+	// Verify that we're going to install underlying libs
+	orderOnly := outputJar.OrderOnly.Strings()
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-minus-apex.ravenwood.jar")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/framework-services.ravenwood.jar")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/ravenwood-runtime-jni.so")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-runtime/lib64/libred.so")
+	android.AssertStringListContains(t, "orderOnly", orderOnly, installPathPrefix+"/ravenwood-utils/framework-rules.ravenwood.jar")
+}
diff --git a/python/scripts/precompile_python.py b/python/scripts/precompile_python.py
index 80e7c76..aa1a5df 100644
--- a/python/scripts/precompile_python.py
+++ b/python/scripts/precompile_python.py
@@ -24,7 +24,12 @@
 # This file needs to support both python 2 and 3.
 
 
-def process_one_file(info, infile, outzip):
+def process_one_file(name, infile, outzip):
+    # Create a ZipInfo instance with a fixed date to ensure a deterministic output.
+    # Date was chosen to be the same as
+    # https://cs.android.com/android/platform/superproject/main/+/main:build/soong/jar/jar.go;l=36;drc=2863e4535eb65e15f955dc8ed48fa99b1d2a1db5
+    info = zipfile.ZipInfo(filename=name, date_time=(2008, 1, 1, 0, 0, 0))
+
     if not info.filename.endswith('.py'):
         outzip.writestr(info, infile.read())
         return
@@ -37,17 +42,15 @@
     with tempfile.NamedTemporaryFile(prefix="Soong_precompile_", delete=False) as tmp:
         out_name = tmp.name
     try:
-        # Ensure deterministic pyc by using the hash rather than timestamp.
-        # This is required to improve caching in accelerated builds.
-        # Only works on Python 3.7+ (see https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode)
-        # which should cover most updated branches and developer machines.
+        # Ensure a deterministic .pyc output by using the hash rather than the timestamp.
+        # Only works on Python 3.7+
+        # See https://docs.python.org/3/library/py_compile.html#py_compile.PycInvalidationMode
         if sys.version_info >= (3, 7):
             py_compile.compile(in_name, out_name, info.filename, doraise=True, invalidation_mode=py_compile.PycInvalidationMode.CHECKED_HASH)
         else:
             py_compile.compile(in_name, out_name, info.filename, doraise=True)
         with open(out_name, 'rb') as f:
             info.filename = info.filename + 'c'
-            # Use ZipInfo rather than str to reuse timestamps for deterministic zip files.
             outzip.writestr(info, f.read())
     finally:
         os.remove(in_name)
@@ -62,9 +65,9 @@
 
     with open(args.dst_zip, 'wb') as outf, open(args.src_zip, 'rb') as inf:
         with zipfile.ZipFile(outf, mode='w') as outzip, zipfile.ZipFile(inf, mode='r') as inzip:
-            for info in inzip.infolist():
-                with inzip.open(info.filename, mode='r') as inzipf:
-                    process_one_file(info, inzipf, outzip)
+            for name in inzip.namelist():
+                with inzip.open(name, mode='r') as inzipf:
+                    process_one_file(name, inzipf, outzip)
 
 
 if __name__ == "__main__":
diff --git a/tradefed/config.go b/tradefed/config.go
index 326a006..b015034 100644
--- a/tradefed/config.go
+++ b/tradefed/config.go
@@ -33,6 +33,7 @@
 	pctx.SourcePathVariable("NativeTestConfigTemplate", "build/make/core/native_test_config_template.xml")
 	pctx.SourcePathVariable("PythonBinaryHostMoblyTestConfigTemplate", "build/make/core/python_binary_host_mobly_test_config_template.xml")
 	pctx.SourcePathVariable("PythonBinaryHostTestConfigTemplate", "build/make/core/python_binary_host_test_config_template.xml")
+	pctx.SourcePathVariable("RavenwoodTestConfigTemplate", "build/make/core/ravenwood_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceTestConfigTemplate", "build/make/core/rust_device_test_config_template.xml")
 	pctx.SourcePathVariable("RustHostTestConfigTemplate", "build/make/core/rust_host_test_config_template.xml")
 	pctx.SourcePathVariable("RustDeviceBenchmarkConfigTemplate", "build/make/core/rust_device_benchmark_config_template.xml")
diff --git a/ui/build/androidmk_denylist.go b/ui/build/androidmk_denylist.go
index 9aeaf9d..e7896ab 100644
--- a/ui/build/androidmk_denylist.go
+++ b/ui/build/androidmk_denylist.go
@@ -30,7 +30,8 @@
 	"libcore/",
 	"libnativehelper/",
 	"pdk/",
-	"toolchain/",
+	// Add back toolchain/ once defensive Android.mk files are removed
+	//"toolchain/",
 }
 
 func blockAndroidMks(ctx Context, androidMks []string) {