Merge "Add a persistent bazel server between builds"
diff --git a/OWNERS b/OWNERS
index e18eea1..964e27a 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,7 +4,6 @@
 # AMER
 agespino@google.com
 alexmarquez@google.com
-asmundak@google.com
 ccross@android.com
 colefaust@google.com
 cparsons@google.com
@@ -27,6 +26,4 @@
 jingwen@google.com
 
 # EMEA
-hansson@google.com #{LAST_RESORT_SUGGESTION}
 lberki@google.com
-paulduffin@google.com #{LAST_RESORT_SUGGESTION}
diff --git a/android/apex.go b/android/apex.go
index 3c945ae..358818f 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -817,7 +817,7 @@
 	var flatContent strings.Builder
 
 	fmt.Fprintf(&fullContent, "%s(minSdkVersion:%s):\n", ctx.ModuleName(), minSdkVersion)
-	for _, key := range FirstUniqueStrings(SortedStringKeys(depInfos)) {
+	for _, key := range FirstUniqueStrings(SortedKeys(depInfos)) {
 		info := depInfos[key]
 		toName := fmt.Sprintf("%s(minSdkVersion:%s)", info.To, info.MinSdkVersion)
 		if info.IsExternal {
diff --git a/android/config.go b/android/config.go
index 1f90ad7..6412cb7 100644
--- a/android/config.go
+++ b/android/config.go
@@ -735,10 +735,6 @@
 	return value == "0" || value == "n" || value == "no" || value == "off" || value == "false"
 }
 
-func (c *config) TargetsJava17() bool {
-	return c.IsEnvTrue("EXPERIMENTAL_TARGET_JAVA_VERSION_17")
-}
-
 // EnvDeps returns the environment variables this build depends on. The first
 // call to this function blocks future reads from the environment.
 func (c *config) EnvDeps() map[string]string {
diff --git a/android/defaults.go b/android/defaults.go
index 925eafc..a821b28 100644
--- a/android/defaults.go
+++ b/android/defaults.go
@@ -302,7 +302,7 @@
 			delete(propertiesSet, "visibility")
 
 			// Replace the "*" with the names of all the properties that have been set.
-			protectedProperties = SortedStringKeys(propertiesSet)
+			protectedProperties = SortedKeys(propertiesSet)
 			module.setProtectedProperties(protectedProperties)
 		} else {
 			for _, property := range protectedProperties {
diff --git a/android/module.go b/android/module.go
index 97c9706..58c5464 100644
--- a/android/module.go
+++ b/android/module.go
@@ -3675,7 +3675,7 @@
 	// Ensure ancestor directories are in dirMap
 	// Make directories build their direct subdirectories
 	// Returns a slice of all directories and a slice of top-level directories.
-	dirs := SortedStringKeys(dirMap)
+	dirs := SortedKeys(dirMap)
 	for _, dir := range dirs {
 		dir := parentDir(dir)
 		for dir != "." && dir != "/" {
@@ -3686,7 +3686,7 @@
 			dir = parentDir(dir)
 		}
 	}
-	dirs = SortedStringKeys(dirMap)
+	dirs = SortedKeys(dirMap)
 	var topDirs []string
 	for _, dir := range dirs {
 		p := parentDir(dir)
@@ -3696,7 +3696,7 @@
 			topDirs = append(topDirs, dir)
 		}
 	}
-	return SortedStringKeys(dirMap), topDirs
+	return SortedKeys(dirMap), topDirs
 }
 
 func (c *buildTargetSingleton) GenerateBuildActions(ctx SingletonContext) {
@@ -3782,7 +3782,7 @@
 	}
 
 	// Wrap those into host|host-cross|target phony rules
-	for _, class := range SortedStringKeys(osClass) {
+	for _, class := range SortedKeys(osClass) {
 		ctx.Phony(class, osClass[class]...)
 	}
 }
diff --git a/android/neverallow.go b/android/neverallow.go
index ad9880a..ba5385c 100644
--- a/android/neverallow.go
+++ b/android/neverallow.go
@@ -542,7 +542,7 @@
 		s = append(s, fmt.Sprintf("properties matching: %s", r.props))
 	}
 	if len(r.directDeps) > 0 {
-		s = append(s, fmt.Sprintf("dep(s): %q", SortedStringKeys(r.directDeps)))
+		s = append(s, fmt.Sprintf("dep(s): %q", SortedKeys(r.directDeps)))
 	}
 	if len(r.osClasses) > 0 {
 		s = append(s, fmt.Sprintf("os class(es): %q", r.osClasses))
diff --git a/android/packaging.go b/android/packaging.go
index ecd84a2..4a9b591 100644
--- a/android/packaging.go
+++ b/android/packaging.go
@@ -240,7 +240,7 @@
 // entries into the specified directory.
 func (p *PackagingBase) CopySpecsToDir(ctx ModuleContext, builder *RuleBuilder, specs map[string]PackagingSpec, dir ModuleOutPath) (entries []string) {
 	seenDir := make(map[string]bool)
-	for _, k := range SortedStringKeys(specs) {
+	for _, k := range SortedKeys(specs) {
 		ps := specs[k]
 		destPath := dir.Join(ctx, ps.relPathInPackage).String()
 		destDir := filepath.Dir(destPath)
diff --git a/android/phony.go b/android/phony.go
index 0adbb55..814a9e3 100644
--- a/android/phony.go
+++ b/android/phony.go
@@ -48,7 +48,7 @@
 
 func (p *phonySingleton) GenerateBuildActions(ctx SingletonContext) {
 	p.phonyMap = getPhonyMap(ctx.Config())
-	p.phonyList = SortedStringKeys(p.phonyMap)
+	p.phonyList = SortedKeys(p.phonyMap)
 	for _, phony := range p.phonyList {
 		p.phonyMap[phony] = SortedUniquePaths(p.phonyMap[phony])
 	}
diff --git a/android/sdk_version.go b/android/sdk_version.go
index 8953eae..a7e03dc 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -211,7 +211,29 @@
 	if !s.ApiLevel.IsPreview() {
 		return s.ApiLevel.String(), nil
 	}
-	return ctx.Config().DefaultAppTargetSdk(ctx).String(), nil
+	// Determine the default sdk
+	ret := ctx.Config().DefaultAppTargetSdk(ctx)
+	if !ret.IsPreview() {
+		// If the default sdk has been finalized, return that
+		return ret.String(), nil
+	}
+	// There can be more than one active in-development sdks
+	// If an app is targeting an active sdk, but not the default one, return the requested active sdk.
+	// e.g.
+	// SETUP
+	// In-development: UpsideDownCake, VanillaIceCream
+	// Default: VanillaIceCream
+	// Android.bp
+	// min_sdk_version: `UpsideDownCake`
+	// RETURN
+	// UpsideDownCake and not VanillaIceCream
+	for _, preview := range ctx.Config().PreviewApiLevels() {
+		if s.ApiLevel.String() == preview.String() {
+			return preview.String(), nil
+		}
+	}
+	// Otherwise return the default one
+	return ret.String(), nil
 }
 
 var (
diff --git a/android/soongconfig/modules.go b/android/soongconfig/modules.go
index ed4888d..9239ca9 100644
--- a/android/soongconfig/modules.go
+++ b/android/soongconfig/modules.go
@@ -301,23 +301,6 @@
 	}
 }
 
-// This is a copy of the one available in soong/android/util.go, but depending
-// on the android package causes a cyclic dependency. A refactoring here is to
-// extract common utils out from android/utils.go for other packages like this.
-func sortedStringKeys(m interface{}) []string {
-	v := reflect.ValueOf(m)
-	if v.Kind() != reflect.Map {
-		panic(fmt.Sprintf("%#v is not a map", m))
-	}
-	keys := v.MapKeys()
-	s := make([]string, 0, len(keys))
-	for _, key := range keys {
-		s = append(s, key.String())
-	}
-	sort.Strings(s)
-	return s
-}
-
 // String emits the Soong config variable definitions as Starlark dictionaries.
 func (defs Bp2BuildSoongConfigDefinitions) String() string {
 	ret := ""
diff --git a/android/test_suites.go b/android/test_suites.go
index 55e1da7..b570b23 100644
--- a/android/test_suites.go
+++ b/android/test_suites.go
@@ -57,7 +57,7 @@
 
 func robolectricTestSuite(ctx SingletonContext, files map[string]InstallPaths) WritablePath {
 	var installedPaths InstallPaths
-	for _, module := range SortedStringKeys(files) {
+	for _, module := range SortedKeys(files) {
 		installedPaths = append(installedPaths, files[module]...)
 	}
 	testCasesDir := pathForInstall(ctx, ctx.Config().BuildOS, X86, "testcases", false)
diff --git a/android/util.go b/android/util.go
index 8f4c17d..38e0a4d 100644
--- a/android/util.go
+++ b/android/util.go
@@ -62,40 +62,33 @@
 	return buf.String()
 }
 
-// JoinWithSuffix appends the suffix to each string in the list and
-// returns them joined together with given separator.
-func JoinWithSuffix(strs []string, suffix string, separator string) string {
-	if len(strs) == 0 {
-		return ""
-	}
-
-	var buf strings.Builder
-	buf.WriteString(strs[0])
-	buf.WriteString(suffix)
-	for i := 1; i < len(strs); i++ {
-		buf.WriteString(separator)
-		buf.WriteString(strs[i])
-		buf.WriteString(suffix)
-	}
-	return buf.String()
+// SortedStringKeys returns the keys of the given map in the ascending order.
+//
+// Deprecated: Use SortedKeys instead.
+func SortedStringKeys[V any](m map[string]V) []string {
+	return SortedKeys(m)
 }
 
-// SorterStringKeys returns the keys of the given string-keyed map in the ascending order.
-func SortedStringKeys(m interface{}) []string {
-	v := reflect.ValueOf(m)
-	if v.Kind() != reflect.Map {
-		panic(fmt.Sprintf("%#v is not a map", m))
-	}
-	if v.Len() == 0 {
+type Ordered interface {
+	~string |
+		~float32 | ~float64 |
+		~int | ~int8 | ~int16 | ~int32 | ~int64 |
+		~uint | ~uint8 | ~uint16 | ~uint32 | ~uint64 | ~uintptr
+}
+
+// SortedKeys returns the keys of the given map in the ascending order.
+func SortedKeys[T Ordered, V any](m map[T]V) []T {
+	if len(m) == 0 {
 		return nil
 	}
-	iter := v.MapRange()
-	s := make([]string, 0, v.Len())
-	for iter.Next() {
-		s = append(s, iter.Key().String())
+	ret := make([]T, 0, len(m))
+	for k := range m {
+		ret = append(ret, k)
 	}
-	sort.Strings(s)
-	return s
+	sort.Slice(ret, func(i, j int) bool {
+		return ret[i] < ret[j]
+	})
+	return ret
 }
 
 // stringValues returns the values of the given string-valued map in randomized map order.
diff --git a/android/util_test.go b/android/util_test.go
index 9b9253b..1034d9e 100644
--- a/android/util_test.go
+++ b/android/util_test.go
@@ -641,42 +641,34 @@
 	}
 }
 
-func TestSortedStringKeys(t *testing.T) {
-	testCases := []struct {
-		name     string
-		in       interface{}
-		expected []string
-	}{
-		{
-			name:     "nil",
-			in:       map[string]string(nil),
-			expected: nil,
-		},
-		{
-			name:     "empty",
-			in:       map[string]string{},
-			expected: nil,
-		},
-		{
-			name:     "simple",
-			in:       map[string]string{"a": "foo", "b": "bar"},
-			expected: []string{"a", "b"},
-		},
-		{
-			name:     "interface values",
-			in:       map[string]interface{}{"a": nil, "b": nil},
-			expected: []string{"a", "b"},
-		},
-	}
+func testSortedKeysHelper[K Ordered, V any](t *testing.T, name string, input map[K]V, expected []K) {
+	t.Helper()
+	t.Run(name, func(t *testing.T) {
+		actual := SortedKeys(input)
+		if !reflect.DeepEqual(actual, expected) {
+			t.Errorf("expected %q, got %q", expected, actual)
+		}
+	})
+}
 
-	for _, tt := range testCases {
-		t.Run(tt.name, func(t *testing.T) {
-			got := SortedStringKeys(tt.in)
-			if g, w := got, tt.expected; !reflect.DeepEqual(g, w) {
-				t.Errorf("wanted %q, got %q", w, g)
-			}
-		})
-	}
+func TestSortedKeys(t *testing.T) {
+	testSortedKeysHelper(t, "simple", map[string]string{
+		"b": "bar",
+		"a": "foo",
+	}, []string{
+		"a",
+		"b",
+	})
+	testSortedKeysHelper(t, "ints", map[int]interface{}{
+		10: nil,
+		5:  nil,
+	}, []int{
+		5,
+		10,
+	})
+
+	testSortedKeysHelper(t, "nil", map[string]string(nil), nil)
+	testSortedKeysHelper(t, "empty", map[string]string{}, nil)
 }
 
 func TestSortedStringValues(t *testing.T) {
diff --git a/apex/OWNERS b/apex/OWNERS
deleted file mode 100644
index 8e4ba5c..0000000
--- a/apex/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file * = jiyong@google.com
diff --git a/apex/apex.go b/apex/apex.go
index d7d76d1..88eb72f 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -99,6 +99,10 @@
 	// /system/sepolicy/apex/<module_name>_file_contexts.
 	File_contexts *string `android:"path"`
 
+	// By default, file_contexts is amended by force-labelling / and /apex_manifest.pb as system_file
+	// to avoid mistakes. When set as true, no force-labelling.
+	Use_file_contexts_as_is *bool
+
 	// Path to the canned fs config file for customizing file's uid/gid/mod/capabilities. The
 	// format is /<path_or_glob> <uid> <gid> <mode> [capabilities=0x<cap>], where path_or_glob is a
 	// path or glob pattern for a file or set of files, uid/gid are numerial values of user ID
diff --git a/apex/apex_test.go b/apex/apex_test.go
index b7febe1..c94bbbb 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -784,6 +784,43 @@
 	}
 }
 
+func TestFileContexts(t *testing.T) {
+	for _, useFileContextsAsIs := range []bool{true, false} {
+		prop := ""
+		if useFileContextsAsIs {
+			prop = "use_file_contexts_as_is: true,\n"
+		}
+		ctx := testApex(t, `
+			apex {
+				name: "myapex",
+				key: "myapex.key",
+				file_contexts: "file_contexts",
+				updatable: false,
+				vendor: true,
+				`+prop+`
+			}
+
+			apex_key {
+				name: "myapex.key",
+				public_key: "testkey.avbpubkey",
+				private_key: "testkey.pem",
+			}
+		`, withFiles(map[string][]byte{
+			"file_contexts": nil,
+		}))
+
+		rule := ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("file_contexts")
+		forceLabellingCommand := "apex_manifest\\\\.pb u:object_r:system_file:s0"
+		if useFileContextsAsIs {
+			android.AssertStringDoesNotContain(t, "should force-label",
+				rule.RuleParams.Command, forceLabellingCommand)
+		} else {
+			android.AssertStringDoesContain(t, "shouldn't force-label",
+				rule.RuleParams.Command, forceLabellingCommand)
+		}
+	}
+}
+
 func TestBasicZipApex(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -2128,6 +2165,34 @@
 			min_sdk_version: "30",
 		}
 	`)
+
+	// Skip check for modules compiling against core API surface
+	testApex(t, `
+		apex {
+			name: "myapex",
+			key: "myapex.key",
+			java_libs: ["libfoo"],
+			min_sdk_version: "29",
+		}
+
+		apex_key {
+			name: "myapex.key",
+			public_key: "testkey.avbpubkey",
+			private_key: "testkey.pem",
+		}
+
+		java_library {
+			name: "libfoo",
+			srcs: ["Foo.java"],
+			apex_available: [
+				"myapex",
+			],
+			// Compile against core API surface
+			sdk_version: "core_current",
+			min_sdk_version: "30",
+		}
+	`)
+
 }
 
 func TestApexMinSdkVersion_Okay(t *testing.T) {
@@ -9472,187 +9537,188 @@
 	}
 }
 
-func TestApexStrictUpdtabilityLint(t *testing.T) {
-	bpTemplate := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			java_libs: ["myjavalib"],
-			updatable: %v,
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		java_library {
-			name: "myjavalib",
-			srcs: ["MyClass.java"],
-			apex_available: [ "myapex" ],
-			lint: {
-				strict_updatability_linting: %v,
-			},
-			sdk_version: "current",
-			min_sdk_version: "29",
-		}
-		`
-	fs := android.MockFS{
-		"lint-baseline.xml": nil,
-	}
-
-	testCases := []struct {
-		testCaseName              string
-		apexUpdatable             bool
-		javaStrictUpdtabilityLint bool
-		lintFileExists            bool
-		disallowedFlagExpected    bool
-	}{
-		{
-			testCaseName:              "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
-			apexUpdatable:             true,
-			javaStrictUpdtabilityLint: true,
-			lintFileExists:            false,
-			disallowedFlagExpected:    false,
-		},
-		{
-			testCaseName:              "non-updatable apex respects strict_updatability of javalib",
-			apexUpdatable:             false,
-			javaStrictUpdtabilityLint: false,
-			lintFileExists:            true,
-			disallowedFlagExpected:    false,
-		},
-		{
-			testCaseName:              "non-updatable apex respects strict updatability of javalib",
-			apexUpdatable:             false,
-			javaStrictUpdtabilityLint: true,
-			lintFileExists:            true,
-			disallowedFlagExpected:    true,
-		},
-		{
-			testCaseName:              "updatable apex sets strict updatability of javalib to true",
-			apexUpdatable:             true,
-			javaStrictUpdtabilityLint: false, // will be set to true by mutator
-			lintFileExists:            true,
-			disallowedFlagExpected:    true,
-		},
-	}
-
-	for _, testCase := range testCases {
-		bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint)
-		fixtures := []android.FixturePreparer{}
-		if testCase.lintFileExists {
-			fixtures = append(fixtures, fs.AddToFixture())
-		}
-
-		result := testApex(t, bp, fixtures...)
-		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
-
-		if disallowedFlagActual != testCase.disallowedFlagExpected {
-			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-		}
-	}
-}
-
-func TestUpdatabilityLintSkipLibcore(t *testing.T) {
-	bp := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			java_libs: ["myjavalib"],
-			updatable: true,
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		java_library {
-			name: "myjavalib",
-			srcs: ["MyClass.java"],
-			apex_available: [ "myapex" ],
-			sdk_version: "current",
-			min_sdk_version: "29",
-		}
-		`
-
-	testCases := []struct {
-		testCaseName           string
-		moduleDirectory        string
-		disallowedFlagExpected bool
-	}{
-		{
-			testCaseName:           "lintable module defined outside libcore",
-			moduleDirectory:        "",
-			disallowedFlagExpected: true,
-		},
-		{
-			testCaseName:           "lintable module defined in libcore root directory",
-			moduleDirectory:        "libcore/",
-			disallowedFlagExpected: false,
-		},
-		{
-			testCaseName:           "lintable module defined in libcore child directory",
-			moduleDirectory:        "libcore/childdir/",
-			disallowedFlagExpected: true,
-		},
-	}
-
-	for _, testCase := range testCases {
-		lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
-		bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
-		result := testApex(t, "", lintFileCreator, bpFileCreator)
-		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-		cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
-		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
-
-		if disallowedFlagActual != testCase.disallowedFlagExpected {
-			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
-		}
-	}
-}
-
-// checks transtive deps of an apex coming from bootclasspath_fragment
-func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
-	bp := `
-		apex {
-			name: "myapex",
-			key: "myapex.key",
-			bootclasspath_fragments: ["mybootclasspathfragment"],
-			updatable: true,
-			min_sdk_version: "29",
-		}
-		apex_key {
-			name: "myapex.key",
-		}
-		bootclasspath_fragment {
-			name: "mybootclasspathfragment",
-			contents: ["myjavalib"],
-			apex_available: ["myapex"],
-			hidden_api: {
-				split_packages: ["*"],
-			},
-		}
-		java_library {
-			name: "myjavalib",
-			srcs: ["MyClass.java"],
-			apex_available: [ "myapex" ],
-			sdk_version: "current",
-			min_sdk_version: "29",
-			compile_dex: true,
-		}
-		`
-	fs := android.MockFS{
-		"lint-baseline.xml": nil,
-	}
-
-	result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
-	myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
-		t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
-	}
-}
+// TODO(b/193460475): Re-enable this test
+//func TestApexStrictUpdtabilityLint(t *testing.T) {
+//	bpTemplate := `
+//		apex {
+//			name: "myapex",
+//			key: "myapex.key",
+//			java_libs: ["myjavalib"],
+//			updatable: %v,
+//			min_sdk_version: "29",
+//		}
+//		apex_key {
+//			name: "myapex.key",
+//		}
+//		java_library {
+//			name: "myjavalib",
+//			srcs: ["MyClass.java"],
+//			apex_available: [ "myapex" ],
+//			lint: {
+//				strict_updatability_linting: %v,
+//			},
+//			sdk_version: "current",
+//			min_sdk_version: "29",
+//		}
+//		`
+//	fs := android.MockFS{
+//		"lint-baseline.xml": nil,
+//	}
+//
+//	testCases := []struct {
+//		testCaseName              string
+//		apexUpdatable             bool
+//		javaStrictUpdtabilityLint bool
+//		lintFileExists            bool
+//		disallowedFlagExpected    bool
+//	}{
+//		{
+//			testCaseName:              "lint-baseline.xml does not exist, no disallowed flag necessary in lint cmd",
+//			apexUpdatable:             true,
+//			javaStrictUpdtabilityLint: true,
+//			lintFileExists:            false,
+//			disallowedFlagExpected:    false,
+//		},
+//		{
+//			testCaseName:              "non-updatable apex respects strict_updatability of javalib",
+//			apexUpdatable:             false,
+//			javaStrictUpdtabilityLint: false,
+//			lintFileExists:            true,
+//			disallowedFlagExpected:    false,
+//		},
+//		{
+//			testCaseName:              "non-updatable apex respects strict updatability of javalib",
+//			apexUpdatable:             false,
+//			javaStrictUpdtabilityLint: true,
+//			lintFileExists:            true,
+//			disallowedFlagExpected:    true,
+//		},
+//		{
+//			testCaseName:              "updatable apex sets strict updatability of javalib to true",
+//			apexUpdatable:             true,
+//			javaStrictUpdtabilityLint: false, // will be set to true by mutator
+//			lintFileExists:            true,
+//			disallowedFlagExpected:    true,
+//		},
+//	}
+//
+//	for _, testCase := range testCases {
+//		bp := fmt.Sprintf(bpTemplate, testCase.apexUpdatable, testCase.javaStrictUpdtabilityLint)
+//		fixtures := []android.FixturePreparer{}
+//		if testCase.lintFileExists {
+//			fixtures = append(fixtures, fs.AddToFixture())
+//		}
+//
+//		result := testApex(t, bp, fixtures...)
+//		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+//		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+//		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi")
+//
+//		if disallowedFlagActual != testCase.disallowedFlagExpected {
+//			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+//		}
+//	}
+//}
+//
+//func TestUpdatabilityLintSkipLibcore(t *testing.T) {
+//	bp := `
+//		apex {
+//			name: "myapex",
+//			key: "myapex.key",
+//			java_libs: ["myjavalib"],
+//			updatable: true,
+//			min_sdk_version: "29",
+//		}
+//		apex_key {
+//			name: "myapex.key",
+//		}
+//		java_library {
+//			name: "myjavalib",
+//			srcs: ["MyClass.java"],
+//			apex_available: [ "myapex" ],
+//			sdk_version: "current",
+//			min_sdk_version: "29",
+//		}
+//		`
+//
+//	testCases := []struct {
+//		testCaseName           string
+//		moduleDirectory        string
+//		disallowedFlagExpected bool
+//	}{
+//		{
+//			testCaseName:           "lintable module defined outside libcore",
+//			moduleDirectory:        "",
+//			disallowedFlagExpected: true,
+//		},
+//		{
+//			testCaseName:           "lintable module defined in libcore root directory",
+//			moduleDirectory:        "libcore/",
+//			disallowedFlagExpected: false,
+//		},
+//		{
+//			testCaseName:           "lintable module defined in libcore child directory",
+//			moduleDirectory:        "libcore/childdir/",
+//			disallowedFlagExpected: true,
+//		},
+//	}
+//
+//	for _, testCase := range testCases {
+//		lintFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"lint-baseline.xml", "")
+//		bpFileCreator := android.FixtureAddTextFile(testCase.moduleDirectory+"Android.bp", bp)
+//		result := testApex(t, "", lintFileCreator, bpFileCreator)
+//		myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+//		sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+//		cmdFlags := fmt.Sprintf("--baseline %vlint-baseline.xml --disallowed_issues NewApi", testCase.moduleDirectory)
+//		disallowedFlagActual := strings.Contains(*sboxProto.Commands[0].Command, cmdFlags)
+//
+//		if disallowedFlagActual != testCase.disallowedFlagExpected {
+//			t.Errorf("Failed testcase: %v \nActual lint cmd: %v", testCase.testCaseName, *sboxProto.Commands[0].Command)
+//		}
+//	}
+//}
+//
+//// checks transtive deps of an apex coming from bootclasspath_fragment
+//func TestApexStrictUpdtabilityLintBcpFragmentDeps(t *testing.T) {
+//	bp := `
+//		apex {
+//			name: "myapex",
+//			key: "myapex.key",
+//			bootclasspath_fragments: ["mybootclasspathfragment"],
+//			updatable: true,
+//			min_sdk_version: "29",
+//		}
+//		apex_key {
+//			name: "myapex.key",
+//		}
+//		bootclasspath_fragment {
+//			name: "mybootclasspathfragment",
+//			contents: ["myjavalib"],
+//			apex_available: ["myapex"],
+//			hidden_api: {
+//				split_packages: ["*"],
+//			},
+//		}
+//		java_library {
+//			name: "myjavalib",
+//			srcs: ["MyClass.java"],
+//			apex_available: [ "myapex" ],
+//			sdk_version: "current",
+//			min_sdk_version: "29",
+//			compile_dex: true,
+//		}
+//		`
+//	fs := android.MockFS{
+//		"lint-baseline.xml": nil,
+//	}
+//
+//	result := testApex(t, bp, dexpreopt.FixtureSetApexBootJars("myapex:myjavalib"), fs.AddToFixture())
+//	myjavalib := result.ModuleForTests("myjavalib", "android_common_apex29")
+//	sboxProto := android.RuleBuilderSboxProtoForTests(t, myjavalib.Output("lint.sbox.textproto"))
+//	if !strings.Contains(*sboxProto.Commands[0].Command, "--baseline lint-baseline.xml --disallowed_issues NewApi") {
+//		t.Errorf("Strict updabality lint missing in myjavalib coming from bootclasspath_fragment mybootclasspath-fragment\nActual lint cmd: %v", *sboxProto.Commands[0].Command)
+//	}
+//}
 
 // updatable apexes should propagate updatable=true to its apps
 func TestUpdatableApexEnforcesAppUpdatability(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index a62f63c..ee6c473 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -333,6 +333,8 @@
 		ctx.PropertyErrorf("file_contexts", "cannot find file_contexts file: %q", fileContexts.String())
 	}
 
+	useFileContextsAsIs := proptools.Bool(a.properties.Use_file_contexts_as_is)
+
 	output := android.PathForModuleOut(ctx, "file_contexts")
 	rule := android.NewRuleBuilder(pctx, ctx)
 
@@ -344,9 +346,11 @@
 		rule.Command().Text("cat").Input(fileContexts).Text(">>").Output(output)
 		// new line
 		rule.Command().Text("echo").Text(">>").Output(output)
-		// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-		rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
-		rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+		if !useFileContextsAsIs {
+			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
+			rule.Command().Text("echo").Flag("/apex_manifest\\\\.pb u:object_r:system_file:s0").Text(">>").Output(output)
+			rule.Command().Text("echo").Flag("/ u:object_r:system_file:s0").Text(">>").Output(output)
+		}
 	case flattenedApex:
 		// For flattened apexes, install path should be prepended.
 		// File_contexts file should be emiited to make via LOCAL_FILE_CONTEXTS
@@ -359,9 +363,11 @@
 		rule.Command().Text("awk").Text(`'/object_r/{printf("` + apexPath + `%s\n", $0)}'`).Input(fileContexts).Text(">").Output(output)
 		// new line
 		rule.Command().Text("echo").Text(">>").Output(output)
-		// force-label /apex_manifest.pb and / as system_file so that apexd can read them
-		rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
-		rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+		if !useFileContextsAsIs {
+			// force-label /apex_manifest.pb and / as system_file so that apexd can read them
+			rule.Command().Text("echo").Flag(apexPath + `/apex_manifest\\.pb u:object_r:system_file:s0`).Text(">>").Output(output)
+			rule.Command().Text("echo").Flag(apexPath + "/ u:object_r:system_file:s0").Text(">>").Output(output)
+		}
 	default:
 		panic(fmt.Errorf("unsupported type %v", a.properties.ApexType))
 	}
@@ -543,7 +549,7 @@
 
 	if len(installMapSet) > 0 {
 		var installs []string
-		installs = append(installs, android.SortedStringKeys(installMapSet)...)
+		installs = append(installs, android.SortedKeys(installMapSet)...)
 		a.SetLicenseInstallMap(installs)
 	}
 
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 062eba8..d1dfb9d 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -17,21 +17,57 @@
 import (
 	"fmt"
 	"os"
+	"path/filepath"
 	"strings"
 
 	"android/soong/android"
 	"android/soong/bazel"
+	"android/soong/shared"
 )
 
+func deleteFilesExcept(ctx *CodegenContext, rootOutputPath android.OutputPath, except []BazelFile) {
+	// Delete files that should no longer be present.
+	bp2buildDirAbs := shared.JoinPath(ctx.topDir, rootOutputPath.String())
+
+	filesToDelete := make(map[string]struct{})
+	err := filepath.Walk(bp2buildDirAbs,
+		func(path string, info os.FileInfo, err error) error {
+			if err != nil {
+				return err
+			}
+			if !info.IsDir() {
+				relPath, err := filepath.Rel(bp2buildDirAbs, path)
+				if err != nil {
+					return err
+				}
+				filesToDelete[relPath] = struct{}{}
+			}
+			return nil
+		})
+	if err != nil {
+		fmt.Printf("ERROR reading %s: %s", bp2buildDirAbs, err)
+		os.Exit(1)
+	}
+
+	for _, bazelFile := range except {
+		filePath := filepath.Join(bazelFile.Dir, bazelFile.Basename)
+		delete(filesToDelete, filePath)
+	}
+	for f, _ := range filesToDelete {
+		absPath := shared.JoinPath(bp2buildDirAbs, f)
+		if err := os.RemoveAll(absPath); err != nil {
+			fmt.Printf("ERROR deleting %s: %s", absPath, err)
+			os.Exit(1)
+		}
+	}
+}
+
 // Codegen is the backend of bp2build. The code generator is responsible for
 // writing .bzl files that are equivalent to Android.bp files that are capable
 // of being built with Bazel.
 func Codegen(ctx *CodegenContext) *CodegenMetrics {
 	// This directory stores BUILD files that could be eventually checked-in.
 	bp2buildDir := android.PathForOutput(ctx, "bp2build")
-	if err := android.RemoveAllOutputDir(bp2buildDir); err != nil {
-		fmt.Printf("ERROR: Encountered error while cleaning %s: %s", bp2buildDir, err.Error())
-	}
 
 	res, errs := GenerateBazelTargets(ctx, true)
 	if len(errs) > 0 {
@@ -44,6 +80,12 @@
 	}
 	bp2buildFiles := CreateBazelFiles(ctx.Config(), nil, res.buildFileToTargets, ctx.mode)
 	writeFiles(ctx, bp2buildDir, bp2buildFiles)
+	// Delete files under the bp2build root which weren't just written. An
+	// alternative would have been to delete the whole directory and write these
+	// files. However, this would regenerate files which were otherwise unchanged
+	// since the last bp2build run, which would have negative incremental
+	// performance implications.
+	deleteFilesExcept(ctx, bp2buildDir, bp2buildFiles)
 
 	injectionFiles, err := CreateSoongInjectionDirFiles(ctx, res.metrics)
 	if err != nil {
@@ -51,7 +93,6 @@
 		os.Exit(1)
 	}
 	writeFiles(ctx, android.PathForOutput(ctx, bazel.SoongInjectionDirName), injectionFiles)
-
 	return &res.metrics
 }
 
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 6c6631a..ced779c 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -227,7 +227,7 @@
 // the generated attributes are sorted to ensure determinism.
 func propsToAttributes(props map[string]string) string {
 	var attributes string
-	for _, propName := range android.SortedStringKeys(props) {
+	for _, propName := range android.SortedKeys(props) {
 		attributes += fmt.Sprintf("    %s = %s,\n", propName, props[propName])
 	}
 	return attributes
diff --git a/bp2build/bzl_conversion.go b/bp2build/bzl_conversion.go
index 992cc1c..e774fdf 100644
--- a/bp2build/bzl_conversion.go
+++ b/bp2build/bzl_conversion.go
@@ -83,7 +83,7 @@
 func generateSoongModuleBzl(bzlLoads map[string]RuleShim) string {
 	var loadStmts string
 	var moduleRuleMap string
-	for _, bzlFileName := range android.SortedStringKeys(bzlLoads) {
+	for _, bzlFileName := range android.SortedKeys(bzlLoads) {
 		loadStmt := "load(\"//build/bazel/queryview_rules:"
 		loadStmt += bzlFileName
 		loadStmt += ".bzl\""
@@ -104,7 +104,7 @@
 
 	rules := make(map[string][]rule)
 	// TODO: allow registration of a bzl rule when registring a factory
-	for _, moduleType := range android.SortedStringKeys(moduleTypeFactories) {
+	for _, moduleType := range android.SortedKeys(moduleTypeFactories) {
 		factory := moduleTypeFactories[moduleType]
 		factoryName := runtime.FuncForPC(reflect.ValueOf(factory).Pointer()).Name()
 		pkg := strings.Split(factoryName, ".")[0]
@@ -221,7 +221,7 @@
 	}
 
 	properties := make([]property, 0, len(propertiesByName))
-	for _, key := range android.SortedStringKeys(propertiesByName) {
+	for _, key := range android.SortedKeys(propertiesByName) {
 		properties = append(properties, propertiesByName[key])
 	}
 
diff --git a/bp2build/configurability.go b/bp2build/configurability.go
index 2a0a78e..8e17103 100644
--- a/bp2build/configurability.go
+++ b/bp2build/configurability.go
@@ -256,7 +256,7 @@
 	}
 
 	var selects string
-	for _, selectKey := range android.SortedStringKeys(selectMap) {
+	for _, selectKey := range android.SortedKeys(selectMap) {
 		if selectKey == bazel.ConditionsDefaultSelectKey {
 			// Handle default condition later.
 			continue
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 47cd2b4..6a39e25 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -105,7 +105,7 @@
 
 func createBuildFiles(buildToTargets map[string]BazelTargets, mode CodegenMode) []BazelFile {
 	files := make([]BazelFile, 0, len(buildToTargets))
-	for _, dir := range android.SortedStringKeys(buildToTargets) {
+	for _, dir := range android.SortedKeys(buildToTargets) {
 		targets := buildToTargets[dir]
 		targets.sort()
 
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 7e29fac..a020650 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -51,7 +51,7 @@
 // Print the codegen metrics to stdout.
 func (metrics *CodegenMetrics) Print() {
 	generatedTargetCount := uint64(0)
-	for _, ruleClass := range android.SortedStringKeys(metrics.serialized.RuleClassCount) {
+	for _, ruleClass := range android.SortedKeys(metrics.serialized.RuleClassCount) {
 		count := metrics.serialized.RuleClassCount[ruleClass]
 		fmt.Printf("[bp2build] %s: %d targets\n", ruleClass, count)
 		generatedTargetCount += count
diff --git a/bp2build/testing.go b/bp2build/testing.go
index 92a9bf1..43baf98 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -230,11 +230,11 @@
 	actualTargets := b.buildFileToTargets
 
 	// Generate the sorted set of directories to check.
-	dirsToCheck := android.SortedStringKeys(expectedTargets)
+	dirsToCheck := android.SortedKeys(expectedTargets)
 	if !ignoreUnexpected {
 		// This needs to perform an exact match so add the directories in which targets were
 		// produced to the list of directories to check.
-		dirsToCheck = append(dirsToCheck, android.SortedStringKeys(actualTargets)...)
+		dirsToCheck = append(dirsToCheck, android.SortedKeys(actualTargets)...)
 		dirsToCheck = android.SortedUniqueStrings(dirsToCheck)
 	}
 
@@ -579,7 +579,7 @@
 	if name != "" {
 		attrStrings = append(attrStrings, fmt.Sprintf(`    name = "%s",`, name))
 	}
-	for _, k := range android.SortedStringKeys(attrs) {
+	for _, k := range android.SortedKeys(attrs) {
 		attrStrings = append(attrStrings, fmt.Sprintf("    %s = %s,", k, attrs[k]))
 	}
 	return fmt.Sprintf(`%s(
diff --git a/cc/OWNERS b/cc/OWNERS
index ffbf14a..c4d82d2 100644
--- a/cc/OWNERS
+++ b/cc/OWNERS
@@ -1,4 +1 @@
 per-file ndk_*.go = danalbert@google.com
-per-file tidy*.go = srhines@google.com, chh@google.com
-per-file afdo.go,afdo_test.go,lto.go,pgo.go = srhines@google.com, pirama@google.com, yikong@google.com
-per-file coverage.go = pirama@google.com, srhines@google.com, allenhair@google.com
diff --git a/cc/bp2build.go b/cc/bp2build.go
index 808f51c..9751a2e 100644
--- a/cc/bp2build.go
+++ b/cc/bp2build.go
@@ -1263,7 +1263,7 @@
 	// result in duplicate library errors for bionic OSes. Here, we explicitly exclude those libraries
 	// from bionic OSes and the no config case as these libraries only build for bionic OSes.
 	if la.systemDynamicDeps.IsNil() && len(la.usedSystemDynamicDepAsDynamicDep) > 0 {
-		toRemove := bazelLabelForSharedDeps(ctx, android.SortedStringKeys(la.usedSystemDynamicDepAsDynamicDep))
+		toRemove := bazelLabelForSharedDeps(ctx, android.SortedKeys(la.usedSystemDynamicDepAsDynamicDep))
 		la.dynamicDeps.Exclude(bazel.NoConfigAxis, "", toRemove)
 		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "android", toRemove)
 		la.dynamicDeps.Exclude(bazel.OsConfigurationAxis, "linux_bionic", toRemove)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 0d03b73..b02e037 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -3930,7 +3930,7 @@
 
 func assertMapKeys(t *testing.T, m map[string]string, expected []string) {
 	t.Helper()
-	assertArrayString(t, android.SortedStringKeys(m), expected)
+	assertArrayString(t, android.SortedKeys(m), expected)
 }
 
 func TestDefaults(t *testing.T) {
diff --git a/cc/library_sdk_member.go b/cc/library_sdk_member.go
index 1bcbdc5..e743bb6 100644
--- a/cc/library_sdk_member.go
+++ b/cc/library_sdk_member.go
@@ -405,7 +405,7 @@
 	}
 
 	// Add the collated include dir properties to the output.
-	for _, property := range android.SortedStringKeys(includeDirs) {
+	for _, property := range android.SortedKeys(includeDirs) {
 		outputProperties.AddProperty(property, includeDirs[property])
 	}
 
diff --git a/cc/ndk_api_coverage_parser/OWNERS b/cc/ndk_api_coverage_parser/OWNERS
deleted file mode 100644
index a90c48c..0000000
--- a/cc/ndk_api_coverage_parser/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-sophiez@google.com
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 66f459a..aa61453 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -1716,9 +1716,9 @@
 // These are to be used by use_soong_sanitized_static_libraries.
 // See build/make/core/binary.mk for more details.
 func (s *sanitizerStaticLibsMap) exportToMake(ctx android.MakeVarsContext) {
-	for _, image := range android.SortedStringKeys(s.libsMap) {
+	for _, image := range android.SortedKeys(s.libsMap) {
 		archMap := s.libsMap[ImageVariantType(image)]
-		for _, arch := range android.SortedStringKeys(archMap) {
+		for _, arch := range android.SortedKeys(archMap) {
 			libs := archMap[arch]
 			sort.Strings(libs)
 
diff --git a/cc/stub_library.go b/cc/stub_library.go
index 76da782..f324dcc 100644
--- a/cc/stub_library.go
+++ b/cc/stub_library.go
@@ -73,7 +73,7 @@
 
 func (s *stubLibraries) MakeVars(ctx android.MakeVarsContext) {
 	// Convert stub library file names into Makefile variable.
-	ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedStringKeys(s.stubLibraryMap), " "))
+	ctx.Strict("STUB_LIBRARIES", strings.Join(android.SortedKeys(s.stubLibraryMap), " "))
 
 	// Export the list of API XML files to Make.
 	sort.Strings(s.apiListCoverageXmlPaths)
diff --git a/cc/util.go b/cc/util.go
index 4e10037..aa0f6b5 100644
--- a/cc/util.go
+++ b/cc/util.go
@@ -118,7 +118,7 @@
 // ...
 func installMapListFileRule(ctx android.SingletonContext, m map[string]string, path string) android.OutputPath {
 	var txtBuilder strings.Builder
-	for idx, k := range android.SortedStringKeys(m) {
+	for idx, k := range android.SortedKeys(m) {
 		if idx > 0 {
 			txtBuilder.WriteString("\n")
 		}
diff --git a/cc/vndk.go b/cc/vndk.go
index 6ab4734..3b7c87d 100644
--- a/cc/vndk.go
+++ b/cc/vndk.go
@@ -876,7 +876,7 @@
 	})
 
 	ctx.Strict("LLNDK_MOVED_TO_APEX_LIBRARIES",
-		strings.Join(android.SortedStringKeys(movedToApexLlndkLibraries), " "))
+		strings.Join(android.SortedKeys(movedToApexLlndkLibraries), " "))
 
 	ctx.Strict("VNDK_LIBRARIES_FILE", c.vndkLibrariesFile.String())
 	ctx.Strict("SOONG_VNDK_SNAPSHOT_ZIP", c.vndkSnapshotZipFile.String())
diff --git a/dexpreopt/OWNERS b/dexpreopt/OWNERS
deleted file mode 100644
index 5a2a198..0000000
--- a/dexpreopt/OWNERS
+++ /dev/null
@@ -1 +0,0 @@
-per-file * = ngeoffray@google.com,calin@google.com,skvadrik@google.com
diff --git a/docs/OWNERS b/docs/OWNERS
deleted file mode 100644
index 2d71271..0000000
--- a/docs/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-per-file map_files.md = danalbert@google.com, enh@google.com, jiyong@google.com
-per-file native_code_coverage.md = pirama@google.com, srhines@google.com, allenhair@google.com
-per-file tidy.md = chh@google.com, srhines@google.com
diff --git a/java/OWNERS b/java/OWNERS
deleted file mode 100644
index 5b71b1e..0000000
--- a/java/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file dexpreopt*.go = ngeoffray@google.com,calin@google.com,skvadrik@google.com
-
-# For metalava team to disable lint checks in platform
-per-file droidstubs.go = aurimas@google.com,emberrose@google.com,sjgilbert@google.com
\ No newline at end of file
diff --git a/java/aar.go b/java/aar.go
index a483e13..7cdcbae 100644
--- a/java/aar.go
+++ b/java/aar.go
@@ -219,13 +219,32 @@
 	linkFlags = append(linkFlags, android.JoinWithPrefix(assetDirStrings, "-A "))
 	linkDeps = append(linkDeps, assetDeps...)
 
-	// SDK version flags
-	minSdkVersion, err := sdkContext.MinSdkVersion(ctx).EffectiveVersionString(ctx)
-	if err != nil {
-		ctx.ModuleErrorf("invalid minSdkVersion: %s", err)
+	// Returns the effective version for {min|target}_sdk_version
+	effectiveVersionString := func(sdkVersion android.SdkSpec, minSdkVersion android.SdkSpec) string {
+		// If {min|target}_sdk_version is current, use sdk_version to determine the effective level
+		// This is necessary for vendor modules.
+		// The effective version does not _only_ depend on {min|target}_sdk_version(level),
+		// but also on the sdk_version (kind+level)
+		if minSdkVersion.ApiLevel.IsCurrent() {
+			ret, err := sdkVersion.EffectiveVersionString(ctx)
+			if err != nil {
+				ctx.ModuleErrorf("invalid sdk_version: %s", err)
+			}
+			return ret
+		}
+		ret, err := minSdkVersion.EffectiveVersionString(ctx)
+		if err != nil {
+			ctx.ModuleErrorf("invalid min_sdk_version: %s", err)
+		}
+		return ret
 	}
+	// SDK version flags
+	sdkVersion := sdkContext.SdkVersion(ctx)
+	minSdkVersion := effectiveVersionString(sdkVersion, sdkContext.MinSdkVersion(ctx))
 
 	linkFlags = append(linkFlags, "--min-sdk-version "+minSdkVersion)
+	// Use minSdkVersion for target-sdk-version, even if `target_sdk_version` is set
+	// This behavior has been copied from Make.
 	linkFlags = append(linkFlags, "--target-sdk-version "+minSdkVersion)
 
 	// Version code
diff --git a/java/app_test.go b/java/app_test.go
index c77f29d..5b16cea 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -1005,6 +1005,7 @@
 		platformSdkInt        int
 		platformSdkCodename   string
 		platformSdkFinal      bool
+		minSdkVersionBp       string
 		expectedMinSdkVersion string
 		platformApis          bool
 		activeCodenames       []string
@@ -1052,6 +1053,14 @@
 			platformSdkCodename:   "S",
 			activeCodenames:       []string{"S"},
 		},
+		{
+			name:                  "two active SDKs",
+			sdkVersion:            "module_current",
+			minSdkVersionBp:       "UpsideDownCake",
+			expectedMinSdkVersion: "UpsideDownCake", // And not VanillaIceCream
+			platformSdkCodename:   "VanillaIceCream",
+			activeCodenames:       []string{"UpsideDownCake", "VanillaIceCream"},
+		},
 	}
 
 	for _, moduleType := range []string{"android_app", "android_library"} {
@@ -1061,12 +1070,17 @@
 				if test.platformApis {
 					platformApiProp = "platform_apis: true,"
 				}
+				minSdkVersionProp := ""
+				if test.minSdkVersionBp != "" {
+					minSdkVersionProp = fmt.Sprintf(` min_sdk_version: "%s",`, test.minSdkVersionBp)
+				}
 				bp := fmt.Sprintf(`%s {
 					name: "foo",
 					srcs: ["a.java"],
 					sdk_version: "%s",
 					%s
-				}`, moduleType, test.sdkVersion, platformApiProp)
+					%s
+				}`, moduleType, test.sdkVersion, platformApiProp, minSdkVersionProp)
 
 				result := android.GroupFixturePreparers(
 					prepareForJavaTest,
diff --git a/java/base.go b/java/base.go
index e7e3d8f..85f4a5e 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1003,7 +1003,7 @@
 					topLevelDirs[srcFileParts[0]] = true
 				}
 			}
-			patchPaths = append(patchPaths, android.SortedStringKeys(topLevelDirs)...)
+			patchPaths = append(patchPaths, android.SortedKeys(topLevelDirs)...)
 
 			classPath := flags.classpath.FormJavaClassPath("")
 			if classPath != "" {
@@ -1845,15 +1845,18 @@
 
 // Implements android.ApexModule
 func (j *Module) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error {
-	sdkSpec := j.MinSdkVersion(ctx)
-	if !sdkSpec.Specified() {
+	sdkVersionSpec := j.SdkVersion(ctx)
+	minSdkVersionSpec := j.MinSdkVersion(ctx)
+	if !minSdkVersionSpec.Specified() {
 		return fmt.Errorf("min_sdk_version is not specified")
 	}
-	if sdkSpec.Kind == android.SdkCore {
+	// If the module is compiling against core (via sdk_version), skip comparison check.
+	if sdkVersionSpec.Kind == android.SdkCore {
 		return nil
 	}
-	if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
-		return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
+	minSdkVersion := minSdkVersionSpec.ApiLevel
+	if minSdkVersion.GreaterThan(sdkVersion) {
+		return fmt.Errorf("newer SDK(%v)", minSdkVersion)
 	}
 	return nil
 }
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 585f818..c07a94a 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -440,7 +440,7 @@
 		return dexJar, nil
 	} else {
 		return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s",
-			name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", "))
+			name, strings.Join(android.SortedKeys(i.contentModuleDexJarPaths), ", "))
 	}
 }
 
@@ -709,7 +709,7 @@
 	imageName := *imageNamePtr
 	imageConfig := imageConfigs[imageName]
 	if imageConfig == nil {
-		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", "))
+		ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedKeys(imageConfigs), ", "))
 		return nil
 	}
 	return imageConfig
diff --git a/java/classpath_fragment.go b/java/classpath_fragment.go
index 259e977..cf81ddb 100644
--- a/java/classpath_fragment.go
+++ b/java/classpath_fragment.go
@@ -111,7 +111,7 @@
 			ctx.PropertyErrorf("contents", "%v is not a ModuleWithStem", name)
 		}
 	}
-	return android.SortedStringKeys(set)
+	return android.SortedKeys(set)
 }
 
 // Converts android.ConfiguredJarList into a list of classpathJars for each given classpathType.
diff --git a/java/dexpreopt_bootjars.go b/java/dexpreopt_bootjars.go
index f2079b0..373b478 100644
--- a/java/dexpreopt_bootjars.go
+++ b/java/dexpreopt_bootjars.go
@@ -538,8 +538,8 @@
 func copyBootJarsToPredefinedLocations(ctx android.ModuleContext, srcBootDexJarsByModule bootDexJarByModule, dstBootJarsByModule map[string]android.WritablePath) {
 	// Create the super set of module names.
 	names := []string{}
-	names = append(names, android.SortedStringKeys(srcBootDexJarsByModule)...)
-	names = append(names, android.SortedStringKeys(dstBootJarsByModule)...)
+	names = append(names, android.SortedKeys(srcBootDexJarsByModule)...)
+	names = append(names, android.SortedKeys(dstBootJarsByModule)...)
 	names = android.SortedUniqueStrings(names)
 	for _, name := range names {
 		src := srcBootDexJarsByModule[name]
@@ -760,8 +760,13 @@
 		FlagWithArg("--android-root=", global.EmptyDirectory).
 		FlagWithArg("--no-inline-from=", "core-oj.jar").
 		Flag("--force-determinism").
-		Flag("--abort-on-hard-verifier-error").
-		FlagWithArg("--compiler-filter=", image.compilerFilter)
+		Flag("--abort-on-hard-verifier-error")
+
+	// If the image is profile-guided but the profile is disabled, we omit "--compiler-filter" to
+	// leave the decision to dex2oat to pick the compiler filter.
+	if !(image.isProfileGuided() && global.DisableGenerateProfile) {
+		cmd.FlagWithArg("--compiler-filter=", image.compilerFilter)
+	}
 
 	// Use the default variant/features for host builds.
 	// The map below contains only device CPU info (which might be x86 on some devices).
diff --git a/java/droiddoc.go b/java/droiddoc.go
index 01a2c14..e98b9ea 100644
--- a/java/droiddoc.go
+++ b/java/droiddoc.go
@@ -603,12 +603,10 @@
 		Flag("-J-XX:-OmitStackTraceInFastThrow").
 		Flag("-XDignore.symbol.file").
 		Flag("--ignore-source-errors").
-		// b/240421555: use a stub doclet until Doclava works with JDK 17
-		//FlagWithArg("-doclet ", "com.google.doclava.Doclava").
-		FlagWithArg("-doclet ", "com.google.stubdoclet.StubDoclet").
+		FlagWithArg("-doclet ", "com.google.doclava.Doclava").
 		FlagWithInputList("-docletpath ", docletPath.Paths(), ":").
-		FlagWithArg("-Xmaxerrs ", "1").
-		FlagWithArg("-Xmaxwarns ", "1").
+		FlagWithArg("-Xmaxerrs ", "10").
+		FlagWithArg("-Xmaxwarns ", "10").
 		Flag("-J--add-exports=jdk.javadoc/jdk.javadoc.internal.doclets.formats.html=ALL-UNNAMED").
 		Flag("-J--add-exports=jdk.compiler/com.sun.tools.javac.util=ALL-UNNAMED").
 		FlagWithArg("-hdf page.build ", ctx.Config().BuildId()+"-$(cat "+buildNumberFile.String()+")").OrderOnly(buildNumberFile).
@@ -780,8 +778,6 @@
 
 	jsilver := ctx.Config().HostJavaToolPath(ctx, "jsilver.jar")
 	doclava := ctx.Config().HostJavaToolPath(ctx, "doclava.jar")
-	// b/240421555: use a stub doclet until Doclava works with JDK 17
-	stubdoclet := ctx.Config().HostJavaToolPath(ctx, "stubdoclet.jar")
 
 	outDir := android.PathForModuleOut(ctx, "out")
 	srcJarDir := android.PathForModuleOut(ctx, "srcjars")
@@ -809,8 +805,7 @@
 	if Bool(d.properties.Dokka_enabled) {
 		desc = "dokka"
 	} else {
-		// b/240421555: use a stub doclet until Doclava works with JDK 17
-		d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava, stubdoclet})
+		d.doclavaDocsFlags(ctx, cmd, classpath{jsilver, doclava})
 
 		for _, o := range d.Javadoc.properties.Out {
 			cmd.ImplicitOutput(android.PathForModuleGen(ctx, o))
@@ -828,9 +823,9 @@
 		FlagWithArg("-C ", outDir.String()).
 		FlagWithArg("-D ", outDir.String())
 
-	// rule.Restat()
+	rule.Restat()
 
-	// zipSyncCleanupCmd(rule, srcJarDir)
+	zipSyncCleanupCmd(rule, srcJarDir)
 
 	rule.Build("javadoc", desc)
 }
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 593d772..be4a48e 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -697,7 +697,7 @@
 // The relative width of APIs is determined by their order in hiddenAPIScopes.
 func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
 	stubDexJars := android.Paths{}
-	modules := android.SortedStringKeys(s)
+	modules := android.SortedKeys(s)
 	for _, module := range modules {
 		stubDexJarsByScope := s[module]
 
@@ -714,7 +714,7 @@
 // the returned list.
 func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths {
 	stubDexJars := android.Paths{}
-	modules := android.SortedStringKeys(s)
+	modules := android.SortedKeys(s)
 	for _, module := range modules {
 		stubDexJarsByScope := s[module]
 		// Not every module will have the same set of
@@ -917,7 +917,7 @@
 // bootDexJars returns the boot dex jar paths sorted by their keys.
 func (b bootDexJarByModule) bootDexJars() android.Paths {
 	paths := android.Paths{}
-	for _, k := range android.SortedStringKeys(b) {
+	for _, k := range android.SortedKeys(b) {
 		paths = append(paths, b[k])
 	}
 	return paths
@@ -927,7 +927,7 @@
 // libraries if present.
 func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
 	paths := android.Paths{}
-	for _, k := range android.SortedStringKeys(b) {
+	for _, k := range android.SortedKeys(b) {
 		if k == "jacocoagent" {
 			continue
 		}
@@ -1217,7 +1217,7 @@
 	// Encode the flags into the boot dex files.
 	encodedBootDexJarsByModule := bootDexJarByModule{}
 	outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
-	for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
+	for _, name := range android.SortedKeys(bootDexInfoByModule) {
 		bootDexInfo := bootDexInfoByModule[name]
 		unencodedDex := bootDexInfo.path
 		encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
@@ -1288,7 +1288,7 @@
 // bootDexJars returns the boot dex jar paths sorted by their keys.
 func (b bootDexInfoByModule) bootDexJars() android.Paths {
 	paths := android.Paths{}
-	for _, m := range android.SortedStringKeys(b) {
+	for _, m := range android.SortedKeys(b) {
 		paths = append(paths, b[m].path)
 	}
 	return paths
diff --git a/java/java.go b/java/java.go
index 27b2a6e..a00e26f 100644
--- a/java/java.go
+++ b/java/java.go
@@ -517,14 +517,8 @@
 		return normalizeJavaVersion(ctx, javaVersion)
 	} else if ctx.Device() {
 		return defaultJavaLanguageVersion(ctx, sdkContext.SdkVersion(ctx))
-	} else if ctx.Config().TargetsJava17() {
-		// Temporary experimental flag to be able to try and build with
-		// java version 17 options.  The flag, if used, just sets Java
-		// 17 as the default version, leaving any components that
-		// target an older version intact.
-		return JAVA_VERSION_17
 	} else {
-		return JAVA_VERSION_11
+		return JAVA_VERSION_17
 	}
 }
 
@@ -1782,7 +1776,7 @@
 
 	rule.Build("metalava", "metalava merged")
 	compiledStubs := android.PathForModuleOut(ctx, ctx.ModuleName(), "stubs.jar")
-	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), "android.jar")
+	al.stubsJar = android.PathForModuleOut(ctx, ctx.ModuleName(), fmt.Sprintf("%s.jar", ctx.ModuleName()))
 
 	var flags javaBuilderFlags
 	flags.javaVersion = getStubsJavaVersion()
@@ -2166,15 +2160,18 @@
 // Implements android.ApexModule
 func (j *Import) ShouldSupportSdkVersion(ctx android.BaseModuleContext,
 	sdkVersion android.ApiLevel) error {
-	sdkSpec := j.MinSdkVersion(ctx)
-	if !sdkSpec.Specified() {
+	sdkVersionSpec := j.SdkVersion(ctx)
+	minSdkVersionSpec := j.MinSdkVersion(ctx)
+	if !minSdkVersionSpec.Specified() {
 		return fmt.Errorf("min_sdk_version is not specified")
 	}
-	if sdkSpec.Kind == android.SdkCore {
+	// If the module is compiling against core (via sdk_version), skip comparison check.
+	if sdkVersionSpec.Kind == android.SdkCore {
 		return nil
 	}
-	if sdkSpec.ApiLevel.GreaterThan(sdkVersion) {
-		return fmt.Errorf("newer SDK(%v)", sdkSpec.ApiLevel)
+	minSdkVersion := minSdkVersionSpec.ApiLevel
+	if minSdkVersion.GreaterThan(sdkVersion) {
+		return fmt.Errorf("newer SDK(%v)", minSdkVersion)
 	}
 	return nil
 }
diff --git a/java/java_test.go b/java/java_test.go
index dc42e9e..05cc23e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -2037,11 +2037,11 @@
 	}{
 		{
 			moduleName:    "bar1",
-			outputJarName: "bar1/android.jar",
+			outputJarName: "bar1/bar1.jar",
 		},
 		{
 			moduleName:    "bar2",
-			outputJarName: "bar2/android.jar",
+			outputJarName: "bar2/bar2.jar",
 		},
 	}
 	for _, c := range testcases {
@@ -2113,7 +2113,7 @@
 		},
 		{
 			moduleName:        "bar2",
-			classPathJarNames: []string{"lib1.jar", "lib2.jar", "bar1/android.jar"},
+			classPathJarNames: []string{"lib1.jar", "lib2.jar", "bar1/bar1.jar"},
 		},
 	}
 	for _, c := range testcases {
@@ -2188,7 +2188,7 @@
 		},
 		{
 			moduleName:        "bar2",
-			staticLibJarNames: []string{"lib1.jar", "lib2.jar", "bar1/android.jar"},
+			staticLibJarNames: []string{"lib1.jar", "lib2.jar", "bar1/bar1.jar"},
 		},
 	}
 	for _, c := range testcases {
diff --git a/java/lint.go b/java/lint.go
index 07b9629..a457d44 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -159,6 +159,50 @@
 	}
 }
 
+type lintDatabaseFiles struct {
+	apiVersionsModule       string
+	apiVersionsCopiedName   string
+	apiVersionsPrebuiltPath string
+	annotationsModule       string
+	annotationCopiedName    string
+	annotationPrebuiltpath  string
+}
+
+var allLintDatabasefiles = map[android.SdkKind]lintDatabaseFiles{
+	android.SdkPublic: {
+		apiVersionsModule:       "api_versions_public",
+		apiVersionsCopiedName:   "api_versions_public.xml",
+		apiVersionsPrebuiltPath: "prebuilts/sdk/current/public/data/api-versions.xml",
+		annotationsModule:       "sdk-annotations.zip",
+		annotationCopiedName:    "annotations-public.zip",
+		annotationPrebuiltpath:  "prebuilts/sdk/current/public/data/annotations.zip",
+	},
+	android.SdkSystem: {
+		apiVersionsModule:       "api_versions_system",
+		apiVersionsCopiedName:   "api_versions_system.xml",
+		apiVersionsPrebuiltPath: "prebuilts/sdk/current/system/data/api-versions.xml",
+		annotationsModule:       "sdk-annotations-system.zip",
+		annotationCopiedName:    "annotations-system.zip",
+		annotationPrebuiltpath:  "prebuilts/sdk/current/system/data/annotations.zip",
+	},
+	android.SdkModule: {
+		apiVersionsModule:       "api_versions_module_lib",
+		apiVersionsCopiedName:   "api_versions_module_lib.xml",
+		apiVersionsPrebuiltPath: "prebuilts/sdk/current/module-lib/data/api-versions.xml",
+		annotationsModule:       "sdk-annotations-module-lib.zip",
+		annotationCopiedName:    "annotations-module-lib.zip",
+		annotationPrebuiltpath:  "prebuilts/sdk/current/module-lib/data/annotations.zip",
+	},
+	android.SdkSystemServer: {
+		apiVersionsModule:       "api_versions_system_server",
+		apiVersionsCopiedName:   "api_versions_system_server.xml",
+		apiVersionsPrebuiltPath: "prebuilts/sdk/current/system-server/data/api-versions.xml",
+		annotationsModule:       "sdk-annotations-system-server.zip",
+		annotationCopiedName:    "annotations-system-server.zip",
+		annotationPrebuiltpath:  "prebuilts/sdk/current/system-server/data/annotations.zip",
+	},
+}
+
 func (l *linter) LintDepSets() LintDepSets {
 	return l.outputs.depSets
 }
@@ -269,19 +313,25 @@
 	cmd.FlagWithInput("@",
 		android.PathForSource(ctx, "build/soong/java/lint_defaults.txt"))
 
-	cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
+	if l.compileSdkKind == android.SdkPublic {
+		cmd.FlagForEachArg("--error_check ", l.extraMainlineLintErrors)
+	} else {
+		// TODO(b/268261262): Remove this branch. We're demoting NewApi to a warning due to pre-existing issues that need to be fixed.
+		cmd.FlagForEachArg("--warning_check ", l.extraMainlineLintErrors)
+	}
 	cmd.FlagForEachArg("--disable_check ", l.properties.Lint.Disabled_checks)
 	cmd.FlagForEachArg("--warning_check ", l.properties.Lint.Warning_checks)
 	cmd.FlagForEachArg("--error_check ", l.properties.Lint.Error_checks)
 	cmd.FlagForEachArg("--fatal_check ", l.properties.Lint.Fatal_checks)
 
-	if l.GetStrictUpdatabilityLinting() {
-		// Verify the module does not baseline issues that endanger safe updatability.
-		if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
-			cmd.FlagWithInput("--baseline ", baselinePath.Path())
-			cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
-		}
-	}
+	// TODO(b/193460475): Re-enable strict updatability linting
+	//if l.GetStrictUpdatabilityLinting() {
+	//	// Verify the module does not baseline issues that endanger safe updatability.
+	//	if baselinePath := l.getBaselineFilepath(ctx); baselinePath.Valid() {
+	//		cmd.FlagWithInput("--baseline ", baselinePath.Path())
+	//		cmd.FlagForEachArg("--disallowed_issues ", updatabilityChecks)
+	//	}
+	//}
 
 	return lintPaths{
 		projectXML: projectXMLPath,
@@ -414,26 +464,17 @@
 	rule.Command().Text("mkdir -p").Flag(lintPaths.cacheDir.String()).Flag(lintPaths.homeDir.String())
 	rule.Command().Text("rm -f").Output(html).Output(text).Output(xml)
 
-	var apiVersionsName, apiVersionsPrebuilt string
-	if l.compileSdkKind == android.SdkModule || l.compileSdkKind == android.SdkSystemServer {
-		// When compiling an SDK module (or system server) we use the filtered
-		// database because otherwise lint's
-		// NewApi check produces too many false positives; This database excludes information
-		// about classes created in mainline modules hence removing those false positives.
-		apiVersionsName = "api_versions_public_filtered.xml"
-		apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions-filtered.xml"
-	} else {
-		apiVersionsName = "api_versions.xml"
-		apiVersionsPrebuilt = "prebuilts/sdk/current/public/data/api-versions.xml"
+	files, ok := allLintDatabasefiles[l.compileSdkKind]
+	if !ok {
+		files = allLintDatabasefiles[android.SdkPublic]
 	}
-
 	var annotationsZipPath, apiVersionsXMLPath android.Path
 	if ctx.Config().AlwaysUsePrebuiltSdks() {
-		annotationsZipPath = android.PathForSource(ctx, "prebuilts/sdk/current/public/data/annotations.zip")
-		apiVersionsXMLPath = android.PathForSource(ctx, apiVersionsPrebuilt)
+		annotationsZipPath = android.PathForSource(ctx, files.annotationPrebuiltpath)
+		apiVersionsXMLPath = android.PathForSource(ctx, files.apiVersionsPrebuiltPath)
 	} else {
-		annotationsZipPath = copiedAnnotationsZipPath(ctx)
-		apiVersionsXMLPath = copiedAPIVersionsXmlPath(ctx, apiVersionsName)
+		annotationsZipPath = copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName)
+		apiVersionsXMLPath = copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName)
 	}
 
 	cmd := rule.Command()
@@ -558,54 +599,39 @@
 		return
 	}
 
-	apiVersionsDb := findModuleOrErr(ctx, "api_versions_public")
-	if apiVersionsDb == nil {
-		if !ctx.Config().AllowMissingDependencies() {
-			ctx.Errorf("lint: missing module api_versions_public")
+	for _, sdk := range android.SortedKeys(allLintDatabasefiles) {
+		files := allLintDatabasefiles[sdk]
+		apiVersionsDb := findModuleOrErr(ctx, files.apiVersionsModule)
+		if apiVersionsDb == nil {
+			if !ctx.Config().AllowMissingDependencies() {
+				ctx.Errorf("lint: missing module api_versions_public")
+			}
+			return
 		}
-		return
-	}
 
-	sdkAnnotations := findModuleOrErr(ctx, "sdk-annotations.zip")
-	if sdkAnnotations == nil {
-		if !ctx.Config().AllowMissingDependencies() {
-			ctx.Errorf("lint: missing module sdk-annotations.zip")
+		sdkAnnotations := findModuleOrErr(ctx, files.annotationsModule)
+		if sdkAnnotations == nil {
+			if !ctx.Config().AllowMissingDependencies() {
+				ctx.Errorf("lint: missing module sdk-annotations.zip")
+			}
+			return
 		}
-		return
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.CpIfChanged,
+			Input:  android.OutputFileForModule(ctx, sdkAnnotations, ""),
+			Output: copiedLintDatabaseFilesPath(ctx, files.annotationCopiedName),
+		})
+
+		ctx.Build(pctx, android.BuildParams{
+			Rule:   android.CpIfChanged,
+			Input:  android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
+			Output: copiedLintDatabaseFilesPath(ctx, files.apiVersionsCopiedName),
+		})
 	}
-
-	filteredDb := findModuleOrErr(ctx, "api-versions-xml-public-filtered")
-	if filteredDb == nil {
-		if !ctx.Config().AllowMissingDependencies() {
-			ctx.Errorf("lint: missing api-versions-xml-public-filtered")
-		}
-		return
-	}
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.CpIfChanged,
-		Input:  android.OutputFileForModule(ctx, sdkAnnotations, ""),
-		Output: copiedAnnotationsZipPath(ctx),
-	})
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.CpIfChanged,
-		Input:  android.OutputFileForModule(ctx, apiVersionsDb, ".api_versions.xml"),
-		Output: copiedAPIVersionsXmlPath(ctx, "api_versions.xml"),
-	})
-
-	ctx.Build(pctx, android.BuildParams{
-		Rule:   android.CpIfChanged,
-		Input:  android.OutputFileForModule(ctx, filteredDb, ""),
-		Output: copiedAPIVersionsXmlPath(ctx, "api_versions_public_filtered.xml"),
-	})
 }
 
-func copiedAnnotationsZipPath(ctx android.PathContext) android.WritablePath {
-	return android.PathForOutput(ctx, "lint", "annotations.zip")
-}
-
-func copiedAPIVersionsXmlPath(ctx android.PathContext, name string) android.WritablePath {
+func copiedLintDatabaseFilesPath(ctx android.PathContext, name string) android.WritablePath {
 	return android.PathForOutput(ctx, "lint", name)
 }
 
diff --git a/java/lint_test.go b/java/lint_test.go
index 62450d5..ec901aa 100644
--- a/java/lint_test.go
+++ b/java/lint_test.go
@@ -113,8 +113,9 @@
 		t.Error("did not use the correct file for baseline")
 	}
 
-	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check NewApi") {
-		t.Error("should check NewApi errors")
+	if !strings.Contains(*sboxProto.Commands[0].Command, "--warning_check NewApi") {
+		// TODO(b/268261262): Change this to check for --error_check
+		t.Error("should check NewApi warnings")
 	}
 
 	if !strings.Contains(*sboxProto.Commands[0].Command, "--error_check SomeCheck") {
@@ -174,55 +175,83 @@
 	}
 }
 
-func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
-	bp := `
-		java_library {
-			name: "foo",
-			srcs: [
-				"a.java",
-			],
-			static_libs: ["bar"],
-			min_sdk_version: "29",
-			sdk_version: "current",
-			lint: {
-				strict_updatability_linting: true,
-			},
-		}
-
-		java_library {
-			name: "bar",
-			srcs: [
-				"a.java",
-			],
-			min_sdk_version: "29",
-			sdk_version: "current",
-		}
-	`
-	fs := android.MockFS{
-		"lint-baseline.xml": nil,
-	}
-
-	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
-		RunTestWithBp(t, bp)
-
-	foo := result.ModuleForTests("foo", "android_common")
-	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command,
-		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
-		t.Error("did not restrict baselining NewApi")
-	}
-
-	bar := result.ModuleForTests("bar", "android_common")
-	sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
-	if !strings.Contains(*sboxProto.Commands[0].Command,
-		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
-		t.Error("did not restrict baselining NewApi")
-	}
-}
+// TODO(b/193460475): Re-enable this test
+//func TestJavaLintStrictUpdatabilityLinting(t *testing.T) {
+//	bp := `
+//		java_library {
+//			name: "foo",
+//			srcs: [
+//				"a.java",
+//			],
+//			static_libs: ["bar"],
+//			min_sdk_version: "29",
+//			sdk_version: "current",
+//			lint: {
+//				strict_updatability_linting: true,
+//			},
+//		}
+//
+//		java_library {
+//			name: "bar",
+//			srcs: [
+//				"a.java",
+//			],
+//			min_sdk_version: "29",
+//			sdk_version: "current",
+//		}
+//	`
+//	fs := android.MockFS{
+//		"lint-baseline.xml": nil,
+//	}
+//
+//	result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, fs.AddToFixture()).
+//		RunTestWithBp(t, bp)
+//
+//	foo := result.ModuleForTests("foo", "android_common")
+//	sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
+//	if !strings.Contains(*sboxProto.Commands[0].Command,
+//		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+//		t.Error("did not restrict baselining NewApi")
+//	}
+//
+//	bar := result.ModuleForTests("bar", "android_common")
+//	sboxProto = android.RuleBuilderSboxProtoForTests(t, bar.Output("lint.sbox.textproto"))
+//	if !strings.Contains(*sboxProto.Commands[0].Command,
+//		"--baseline lint-baseline.xml --disallowed_issues NewApi") {
+//		t.Error("did not restrict baselining NewApi")
+//	}
+//}
 
 func TestJavaLintDatabaseSelectionFull(t *testing.T) {
-	testCases := []string{
-		"current", "core_platform", "system_current", "S", "30", "10000",
+	testCases := []struct {
+		sdk_version   string
+		expected_file string
+	}{
+		{
+			"current",
+			"api_versions_public.xml",
+		}, {
+			"core_platform",
+			"api_versions_public.xml",
+		}, {
+			"system_current",
+			"api_versions_system.xml",
+		}, {
+			"module_current",
+			"api_versions_module_lib.xml",
+		}, {
+			"system_server_current",
+			"api_versions_system_server.xml",
+		}, {
+			"S",
+			"api_versions_public.xml",
+		}, {
+			"30",
+			"api_versions_public.xml",
+		}, {
+			"10000",
+			"api_versions_public.xml",
+		},
 	}
 	bp := `
 		java_library {
@@ -238,7 +267,7 @@
 		}
 `
 	for _, testCase := range testCases {
-		thisBp := strings.Replace(bp, "XXX", testCase, 1)
+		thisBp := strings.Replace(bp, "XXX", testCase.sdk_version, 1)
 
 		result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules, FixtureWithPrebuiltApis(map[string][]string{
 			"30":    {"foo"},
@@ -248,49 +277,8 @@
 
 		foo := result.ModuleForTests("foo", "android_common")
 		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-		if strings.Contains(*sboxProto.Commands[0].Command,
-			"/api_versions_public_filtered.xml") {
-			t.Error("used public-filtered lint api database for case", testCase)
-		}
-		if !strings.Contains(*sboxProto.Commands[0].Command,
-			"/api_versions.xml") {
+		if !strings.Contains(*sboxProto.Commands[0].Command, "/"+testCase.expected_file) {
 			t.Error("did not use full api database for case", testCase)
 		}
 	}
-
-}
-
-func TestJavaLintDatabaseSelectionPublicFiltered(t *testing.T) {
-	testCases := []string{
-		"module_current", "system_server_current",
-	}
-	bp := `
-		java_library {
-			name: "foo",
-			srcs: [
-				"a.java",
-			],
-			min_sdk_version: "29",
-			sdk_version: "XXX",
-			lint: {
-				strict_updatability_linting: true,
-			},
-		}
-`
-	for _, testCase := range testCases {
-		thisBp := strings.Replace(bp, "XXX", testCase, 1)
-		result := android.GroupFixturePreparers(PrepareForTestWithJavaDefaultModules).
-			RunTestWithBp(t, thisBp)
-
-		foo := result.ModuleForTests("foo", "android_common")
-		sboxProto := android.RuleBuilderSboxProtoForTests(t, foo.Output("lint.sbox.textproto"))
-		if !strings.Contains(*sboxProto.Commands[0].Command,
-			"/api_versions_public_filtered.xml") {
-			t.Error("did not use public-filtered lint api database for case", testCase)
-		}
-		if strings.Contains(*sboxProto.Commands[0].Command,
-			"/api_versions.xml") {
-			t.Error("used full api database for case", testCase)
-		}
-	}
 }
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index c6acd55..206d995 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -264,7 +264,7 @@
 	}
 
 	// Sort the keys in order to make build.ninja stable
-	for _, k := range android.SortedStringKeys(latest) {
+	for _, k := range android.SortedKeys(latest) {
 		info := latest[k]
 		name := PrebuiltApiModuleName(info.module, info.scope, "latest")
 		createApiModule(mctx, name, info.path)
@@ -284,7 +284,7 @@
 		}
 	}
 	// Create empty incompatibilities files for remaining modules
-	for _, k := range android.SortedStringKeys(latest) {
+	for _, k := range android.SortedKeys(latest) {
 		if _, ok := incompatibilities[k]; !ok {
 			createEmptyFile(mctx, PrebuiltApiModuleName(latest[k].module+"-incompatibilities", latest[k].scope, "latest"))
 		}
diff --git a/java/sdk.go b/java/sdk.go
index b0da5af..10ae3f6 100644
--- a/java/sdk.go
+++ b/java/sdk.go
@@ -57,14 +57,10 @@
 		return JAVA_VERSION_8
 	} else if sdk.FinalOrFutureInt() <= 31 {
 		return JAVA_VERSION_9
-	} else if ctx.Config().TargetsJava17() {
-		// Temporary experimental flag to be able to try and build with
-		// java version 17 options.  The flag, if used, just sets Java
-		// 17 as the default version, leaving any components that
-		// target an older version intact.
-		return JAVA_VERSION_17
-	} else {
+	} else if sdk.FinalOrFutureInt() <= 32 {
 		return JAVA_VERSION_11
+	} else {
+		return JAVA_VERSION_17
 	}
 }
 
diff --git a/java/sdk_library.go b/java/sdk_library.go
index c168c53..d2fbfd9 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1379,7 +1379,7 @@
 	})
 
 	// Make the set of components exported by this module available for use elsewhere.
-	exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedStringKeys(exportedComponents)}
+	exportedComponentInfo := android.ExportedComponentsInfo{Components: android.SortedKeys(exportedComponents)}
 	ctx.SetProvider(android.ExportedComponentsInfoProvider, exportedComponentInfo)
 
 	// Provide additional information for inclusion in an sdk's generated .info file.
diff --git a/java/testing.go b/java/testing.go
index e6f76e1..63d7dba 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -198,7 +198,7 @@
 				imports_sdk_version: "none",
 				imports_compile_dex: true,
 			}
-		`, strings.Join(android.SortedStringKeys(apiLevel2Modules), `", "`))
+		`, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
 
 	for release, modules := range apiLevel2Modules {
 		mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
diff --git a/licenses/OWNERS b/licenses/OWNERS
deleted file mode 100644
index fddfc48..0000000
--- a/licenses/OWNERS
+++ /dev/null
@@ -1,2 +0,0 @@
-per-file * = bbadour@google.com
-
diff --git a/linkerconfig/proto/OWNERS b/linkerconfig/proto/OWNERS
deleted file mode 100644
index 31f0460..0000000
--- a/linkerconfig/proto/OWNERS
+++ /dev/null
@@ -1,3 +0,0 @@
-kiyoungkim@google.com
-jiyong@google.com
-jooyung@google.com
diff --git a/python/python.go b/python/python.go
index 18e5b68..0ae7b36 100644
--- a/python/python.go
+++ b/python/python.go
@@ -532,7 +532,7 @@
 
 	if len(relativeRootMap) > 0 {
 		// in order to keep stable order of soong_zip params, we sort the keys here.
-		roots := android.SortedStringKeys(relativeRootMap)
+		roots := android.SortedKeys(relativeRootMap)
 
 		// Use -symlinks=false so that the symlinks in the bazel output directory are followed
 		parArgs := []string{"-symlinks=false"}
diff --git a/rust/builder.go b/rust/builder.go
index 5b5c993..a2f1238 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -247,7 +247,13 @@
 	if ctx.Config().IsEnvTrue("SOONG_RUSTC_INCREMENTAL") {
 		incrementalPath := android.PathForOutput(ctx, "rustc").String()
 
-		rustcFlags = append(rustcFlags, "-C incremental="+incrementalPath)
+		rustcFlags = append(rustcFlags, "-Cincremental="+incrementalPath)
+	}
+
+	// Disallow experimental features
+	modulePath := android.PathForModuleSrc(ctx).String()
+	if !(android.IsThirdPartyPath(modulePath) || strings.HasPrefix(modulePath, "prebuilts")) {
+		rustcFlags = append(rustcFlags, "-Zallow-features=\"default_alloc_error_handler,custom_inner_attributes,mixed_integer_ops,slice_internals\"")
 	}
 
 	// Collect linker flags
diff --git a/rust/rust.go b/rust/rust.go
index e4cf671..8a13ba3 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -62,11 +62,11 @@
 }
 
 type BaseProperties struct {
-	AndroidMkRlibs         []string
-	AndroidMkDylibs        []string
-	AndroidMkProcMacroLibs []string
-	AndroidMkSharedLibs    []string
-	AndroidMkStaticLibs    []string
+	AndroidMkRlibs         []string `blueprint:"mutated"`
+	AndroidMkDylibs        []string `blueprint:"mutated"`
+	AndroidMkProcMacroLibs []string `blueprint:"mutated"`
+	AndroidMkSharedLibs    []string `blueprint:"mutated"`
+	AndroidMkStaticLibs    []string `blueprint:"mutated"`
 
 	ImageVariationPrefix string `blueprint:"mutated"`
 	VndkVersion          string `blueprint:"mutated"`
diff --git a/scripts/OWNERS b/scripts/OWNERS
deleted file mode 100644
index 7b003fd..0000000
--- a/scripts/OWNERS
+++ /dev/null
@@ -1,4 +0,0 @@
-per-file system-clang-format,system-clang-format-2 = enh@google.com,smoreland@google.com
-per-file construct_context.py = ngeoffray@google.com,calin@google.com,skvadrik@google.com
-per-file conv_linker_config.py = kiyoungkim@google.com, jiyong@google.com, jooyung@google.com
-per-file gen_ndk*.sh,gen_java*.sh = sophiez@google.com, allenhair@google.com
diff --git a/sdk/update.go b/sdk/update.go
index f50439c..0820d62 100644
--- a/sdk/update.go
+++ b/sdk/update.go
@@ -565,7 +565,7 @@
 	if m.deps != nil {
 		writeObjectPair("@deps", m.deps)
 	}
-	for _, k := range android.SortedStringKeys(m.memberSpecific) {
+	for _, k := range android.SortedKeys(m.memberSpecific) {
 		v := m.memberSpecific[k]
 		writeObjectPair(k, v)
 	}
@@ -626,7 +626,7 @@
 		getModuleInfo(memberVariantDep.variant)
 	}
 
-	for _, memberName := range android.SortedStringKeys(name2Info) {
+	for _, memberName := range android.SortedKeys(name2Info) {
 		info := name2Info[memberName]
 		modules = append(modules, info)
 	}
@@ -1708,7 +1708,7 @@
 		}
 
 		// Create the image variant info in a fixed order.
-		for _, imageVariantName := range android.SortedStringKeys(variantsByImage) {
+		for _, imageVariantName := range android.SortedKeys(variantsByImage) {
 			variants := variantsByImage[imageVariantName]
 			archInfo.imageVariantInfos = append(archInfo.imageVariantInfos, newImageVariantSpecificInfo(ctx, imageVariantName, variantPropertiesFactory, variants))
 		}
diff --git a/tests/bp2build_bazel_test.sh b/tests/bp2build_bazel_test.sh
index 878b4a1..1ff1b5b 100755
--- a/tests/bp2build_bazel_test.sh
+++ b/tests/bp2build_bazel_test.sh
@@ -21,6 +21,68 @@
   fi
 }
 
+# Tests that, if bp2build reruns due to a blueprint file changing, that
+# BUILD files whose contents are unchanged are not regenerated.
+function test_bp2build_unchanged {
+  setup
+
+  mkdir -p pkg
+  touch pkg/x.txt
+  cat > pkg/Android.bp <<'EOF'
+filegroup {
+    name: "x",
+    srcs: ["x.txt"],
+    bazel_module: {bp2build_available: true},
+  }
+EOF
+
+  run_soong bp2build
+  local -r buildfile_mtime1=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+  local -r marker_mtime1=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+  # Force bp2build to rerun by updating the timestamp of a blueprint file.
+  touch pkg/Android.bp
+
+  run_soong bp2build
+  local -r buildfile_mtime2=$(stat -c "%y" out/soong/bp2build/pkg/BUILD.bazel)
+  local -r marker_mtime2=$(stat -c "%y" out/soong/bp2build_workspace_marker)
+
+  if [[ "$marker_mtime1" == "$marker_mtime2" ]]; then
+    fail "Expected bp2build marker file to change"
+  fi
+  if [[ "$buildfile_mtime1" != "$buildfile_mtime2" ]]; then
+    fail "BUILD.bazel was updated even though contents are same"
+  fi
+}
+
+# Tests that blueprint files that are deleted are not present when the
+# bp2build tree is regenerated.
+function test_bp2build_deleted_blueprint {
+  setup
+
+  mkdir -p pkg
+  touch pkg/x.txt
+  cat > pkg/Android.bp <<'EOF'
+filegroup {
+    name: "x",
+    srcs: ["x.txt"],
+    bazel_module: {bp2build_available: true},
+  }
+EOF
+
+  run_soong bp2build
+  if [[ ! -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
+    fail "Expected pkg/BUILD.bazel to be generated"
+  fi
+
+  rm pkg/Android.bp
+
+  run_soong bp2build
+  if [[ -e "./out/soong/bp2build/pkg/BUILD.bazel" ]]; then
+    fail "Expected pkg/BUILD.bazel to be deleted"
+  fi
+}
+
 function test_bp2build_null_build_with_globs {
   setup
 
diff --git a/tests/dcla_apex_comparison_test.sh b/tests/dcla_apex_comparison_test.sh
new file mode 100755
index 0000000..2ecb876
--- /dev/null
+++ b/tests/dcla_apex_comparison_test.sh
@@ -0,0 +1,138 @@
+#!/bin/bash
+
+# Copyright (C) 2023 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.
+
+set -euo pipefail
+
+# Soong/Bazel integration test to build the mainline modules in mixed build and
+# compare the DCLA libs extracted from those modules to ensure they are identical.
+
+if [ ! -e "build/make/core/Makefile" ]; then
+  echo "$0 must be run from the top of the Android source tree."
+  exit 1
+fi
+
+TARGET_PRODUCTS=(
+  module_arm64
+  module_x86_64
+)
+
+MODULES=(
+  # These modules depend on the DCLA libs
+  com.android.adbd
+  com.android.art
+  com.android.art.debug
+  com.android.art.testing
+  com.android.btservices
+  com.android.conscrypt
+  com.android.i18n
+  com.android.media
+  com.android.media.swcodec
+  com.android.resolv
+  com.android.runtime
+  com.android.tethering
+)
+
+DCLA_LIBS=(
+  libbase.so
+  libc++.so
+  libcrypto.so
+  libcutils.so
+)
+
+if [[ -z ${OUT_DIR+x} ]]; then
+  OUT_DIR="out"
+fi
+
+if [[ -z ${ANDROID_HOST_OUT+x} ]]; then
+  export ANDROID_HOST_OUT="out/host/linux-x86"
+fi
+
+######################
+# Build deapexer and debugfs
+######################
+DEAPEXER="${ANDROID_HOST_OUT}/bin/deapexer"
+DEBUGFS="${ANDROID_HOST_OUT}/bin/debugfs"
+if [[ ! -f "${DEAPEXER}" ]] || [[ ! -f "${DEBUGFS}" ]]; then
+  build/soong/soong_ui.bash --make-mode --skip-soong-tests deapexer debugfs
+fi
+
+DEAPEXER="${DEAPEXER} --debugfs_path=${DEBUGFS}"
+
+############
+# Test Setup
+############
+OUTPUT_DIR="$(mktemp -d tmp.XXXXXX)"
+
+function cleanup {
+  rm -rf "${OUTPUT_DIR}"
+}
+trap cleanup EXIT
+
+#######
+# Tests
+#######
+
+function extract_dcla_libs() {
+  local product=$1; shift
+  for module in "${MODULES[@]}"; do
+    local apex="${OUTPUT_DIR}/${product}/${module}.apex"
+    local extract_dir="${OUTPUT_DIR}/${product}/${module}/extract"
+
+    $DEAPEXER extract "${apex}" "${extract_dir}"
+  done
+}
+
+function compare_dcla_libs() {
+  local product=$1; shift
+
+  for lib in "${DCLA_LIBS[@]}"; do
+    for arch in lib lib64; do
+      local prev_sha=""
+      for module in "${MODULES[@]}"; do
+        local file="${OUTPUT_DIR}/${product}/${module}/extract/${arch}/${lib}"
+        if [[ ! -f "${file}" ]]; then
+          # not all libs are present in a module
+          echo "file doesn't exist: ${file}"
+          continue
+        fi
+        sha=$(sha1sum ${file})
+        sha="${sha% *}"
+        if [ "${prev_sha}" == "" ]; then
+          prev_sha="${sha}"
+        elif [ "${sha}" != "${prev_sha}" ]; then
+          echo "Test failed, ${lib} has different hash value"
+          exit 1
+        fi
+      done
+    done
+  done
+}
+
+export UNBUNDLED_BUILD_SDKS_FROM_SOURCE=true # don't rely on prebuilts
+export TARGET_BUILD_APPS="${MODULES[@]}"
+for product in "${TARGET_PRODUCTS[@]}"; do
+  ###########
+  # Build the mainline modules
+  ###########
+  packages/modules/common/build/build_unbundled_mainline_module.sh \
+    --product "${product}" \
+    --dist_dir "${OUTPUT_DIR}/${product}"
+
+  extract_dcla_libs "${product}"
+  compare_dcla_libs "${product}"
+done
+
+echo "Test passed"
diff --git a/tests/run_integration_tests.sh b/tests/run_integration_tests.sh
index 676df23..a91ccf4 100755
--- a/tests/run_integration_tests.sh
+++ b/tests/run_integration_tests.sh
@@ -15,7 +15,7 @@
 # mock client.
 "$TOP/build/soong/tests/apex_comparison_tests.sh"
 "$TOP/build/soong/tests/apex_comparison_tests.sh" "module_arm64only"
-
+"$TOP/build/soong/tests/dcla_apex_comparison_test.sh"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_arm" "armv7-a"
 "$TOP/build/soong/tests/apex_cc_module_arch_variant_tests.sh" "aosp_cf_arm64_phone" "armv8-a" "cortex-a53"
diff --git a/ui/build/ninja.go b/ui/build/ninja.go
index dab1a9b..28f3c38 100644
--- a/ui/build/ninja.go
+++ b/ui/build/ninja.go
@@ -23,10 +23,16 @@
 	"strings"
 	"time"
 
+	"android/soong/shared"
 	"android/soong/ui/metrics"
 	"android/soong/ui/status"
 )
 
+const (
+	// File containing the environment state when ninja is executed
+	ninjaEnvFileName = "ninja.environment"
+)
+
 // Constructs and runs the Ninja command line with a restricted set of
 // environment variables. It's important to restrict the environment Ninja runs
 // for hermeticity reasons, and to avoid spurious rebuilds.
@@ -186,6 +192,21 @@
 		ctx.Verbosef("  %s", envVar)
 	}
 
+	// Write the env vars available during ninja execution to a file
+	ninjaEnvVars := cmd.Environment.AsMap()
+	data, err := shared.EnvFileContents(ninjaEnvVars)
+	if err != nil {
+		ctx.Panicf("Could not parse environment variables for ninja run %s", err)
+	}
+	// Write the file in every single run. This is fine because
+	// 1. It is not a dep of Soong analysis, so will not retrigger Soong analysis.
+	// 2. Is is fairly lightweight (~1Kb)
+	ninjaEnvVarsFile := shared.JoinPath(config.SoongOutDir(), ninjaEnvFileName)
+	err = os.WriteFile(ninjaEnvVarsFile, data, 0666)
+	if err != nil {
+		ctx.Panicf("Could not write ninja environment file %s", err)
+	}
+
 	// Poll the Ninja log for updates regularly based on the heartbeat
 	// frequency. If it isn't updated enough, then we want to surface the
 	// possibility that Ninja is stuck, to the user.
diff --git a/ui/build/path.go b/ui/build/path.go
index 86e61c0..29128d8 100644
--- a/ui/build/path.go
+++ b/ui/build/path.go
@@ -109,6 +109,15 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
+		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
+		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
+			myPath = py2Path + string(os.PathListSeparator) + myPath
+		}
+	} else if value != "" {
+		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
+	}
+
 	// Set $PATH to be the directories containing the host tool symlinks, and
 	// the prebuilts directory for the current host OS.
 	config.Environment().Set("PATH", myPath)
@@ -244,6 +253,15 @@
 	prebuiltsPath, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86")
 	myPath = prebuiltsPath + string(os.PathListSeparator) + myPath
 
+	if value, _ := config.Environment().Get("BUILD_BROKEN_PYTHON_IS_PYTHON2"); value == "true" {
+		py2Path, _ := filepath.Abs("prebuilts/build-tools/path/" + runtime.GOOS + "-x86/py2")
+		if info, err := os.Stat(py2Path); err == nil && info.IsDir() {
+			myPath = py2Path + string(os.PathListSeparator) + myPath
+		}
+	} else if value != "" {
+		ctx.Fatalf("BUILD_BROKEN_PYTHON_IS_PYTHON2 can only be set to 'true' or an empty string, but got %s\n", value)
+	}
+
 	// Replace the $PATH variable with the path_interposer symlinks, and
 	// checked-in prebuilts.
 	config.Environment().Set("PATH", myPath)