Merge "Ignore variable assignments that come after a rule definition"
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index d851a98..6b2be69 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -853,7 +853,8 @@
 		// build statement have later timestamps than the outputs.
 		rule.Restat()
 
-		rule.Build(fmt.Sprintf("bazel %d", index), buildStatement.Mnemonic)
+		desc := fmt.Sprintf("%s: %s", buildStatement.Mnemonic, buildStatement.OutputPaths)
+		rule.Build(fmt.Sprintf("bazel %d", index), desc)
 	}
 }
 
diff --git a/apex/apex.go b/apex/apex.go
index 62013cf..76af1b8 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -19,7 +19,6 @@
 import (
 	"fmt"
 	"path/filepath"
-	"regexp"
 	"sort"
 	"strings"
 
@@ -1657,20 +1656,7 @@
 var _ androidApp = (*java.AndroidApp)(nil)
 var _ androidApp = (*java.AndroidAppImport)(nil)
 
-func sanitizedBuildIdForPath(ctx android.BaseModuleContext) string {
-	buildId := ctx.Config().BuildId()
-
-	// The build ID is used as a suffix for a filename, so ensure that
-	// the set of characters being used are sanitized.
-	// - any word character: [a-zA-Z0-9_]
-	// - dots: .
-	// - dashes: -
-	validRegex := regexp.MustCompile(`^[\w\.\-\_]+$`)
-	if !validRegex.MatchString(buildId) {
-		ctx.ModuleErrorf("Unable to use build id %s as filename suffix, valid characters are [a-z A-Z 0-9 _ . -].", buildId)
-	}
-	return buildId
-}
+const APEX_VERSION_PLACEHOLDER = "__APEX_VERSION_PLACEHOLDER__"
 
 func apexFileForAndroidApp(ctx android.BaseModuleContext, aapp androidApp) apexFile {
 	appDir := "app"
@@ -1681,7 +1667,7 @@
 	// TODO(b/224589412, b/226559955): Ensure that the subdirname is suffixed
 	// so that PackageManager correctly invalidates the existing installed apk
 	// in favour of the new APK-in-APEX.  See bugs for more information.
-	dirInApex := filepath.Join(appDir, aapp.InstallApkName()+"@"+sanitizedBuildIdForPath(ctx))
+	dirInApex := filepath.Join(appDir, aapp.InstallApkName()+"@"+APEX_VERSION_PLACEHOLDER)
 	fileToCopy := aapp.OutputFile()
 
 	af := newApexFile(ctx, fileToCopy, aapp.BaseModuleName(), dirInApex, app, aapp)
@@ -1920,7 +1906,7 @@
 					// suffixed so that PackageManager correctly invalidates the
 					// existing installed apk in favour of the new APK-in-APEX.
 					// See bugs for more information.
-					appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+sanitizedBuildIdForPath(ctx))
+					appDirName := filepath.Join(appDir, ap.BaseModuleName()+"@"+APEX_VERSION_PLACEHOLDER)
 					af := newApexFile(ctx, ap.OutputFile(), ap.BaseModuleName(), appDirName, appSet, ap)
 					af.certificate = java.PresignedCertificate
 					filesInfo = append(filesInfo, af)
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 7b29058..4a52115 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -223,7 +223,6 @@
 		// not because of these tests specifically (it's not used by the tests)
 		variables.Platform_version_active_codenames = []string{"Q", "Tiramisu"}
 		variables.Platform_vndk_version = proptools.StringPtr("29")
-		variables.BuildId = proptools.StringPtr("TEST.BUILD_ID")
 	}),
 )
 
@@ -683,7 +682,7 @@
 		"etc/myetc",
 		"javalib/myjar.jar",
 		"lib64/mylib.so",
-		"app/AppFoo@TEST.BUILD_ID/AppFoo.apk",
+		"app/AppFoo@__APEX_VERSION_PLACEHOLDER__/AppFoo.apk",
 		"overlay/blue/rro.apk",
 		"etc/bpf/bpf.o",
 		"etc/bpf/bpf2.o",
@@ -5683,8 +5682,8 @@
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
-	ensureContains(t, copyCmds, "image.apex/app/AppFoo@TEST.BUILD_ID/AppFoo.apk")
-	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv@TEST.BUILD_ID/AppFooPriv.apk")
+	ensureContains(t, copyCmds, "image.apex/app/AppFoo@__APEX_VERSION_PLACEHOLDER__/AppFoo.apk")
+	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPriv@__APEX_VERSION_PLACEHOLDER__/AppFooPriv.apk")
 
 	appZipRule := ctx.ModuleForTests("AppFoo", "android_common_apex10000").Description("zip jni libs")
 	// JNI libraries are uncompressed
@@ -5701,36 +5700,6 @@
 	}
 }
 
-func TestApexWithAppImportBuildId(t *testing.T) {
-	invalidBuildIds := []string{"../", "a b", "a/b", "a/b/../c", "/a"}
-	for _, id := range invalidBuildIds {
-		message := fmt.Sprintf("Unable to use build id %s as filename suffix", id)
-		fixture := android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
-			variables.BuildId = proptools.StringPtr(id)
-		})
-		testApexError(t, message, `apex {
-			name: "myapex",
-			key: "myapex.key",
-			apps: ["AppFooPrebuilt"],
-			updatable: false,
-		}
-
-		apex_key {
-			name: "myapex.key",
-			public_key: "testkey.avbpubkey",
-			private_key: "testkey.pem",
-		}
-
-		android_app_import {
-			name: "AppFooPrebuilt",
-			apk: "PrebuiltAppFoo.apk",
-			presigned: true,
-			apex_available: ["myapex"],
-		}
-	`, fixture)
-	}
-}
-
 func TestApexWithAppImports(t *testing.T) {
 	ctx := testApex(t, `
 		apex {
@@ -5776,8 +5745,8 @@
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
-	ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt@TEST.BUILD_ID/AppFooPrebuilt.apk")
-	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt@TEST.BUILD_ID/AwesomePrebuiltAppFooPriv.apk")
+	ensureContains(t, copyCmds, "image.apex/app/AppFooPrebuilt@__APEX_VERSION_PLACEHOLDER__/AppFooPrebuilt.apk")
+	ensureContains(t, copyCmds, "image.apex/priv-app/AppFooPrivPrebuilt@__APEX_VERSION_PLACEHOLDER__/AwesomePrebuiltAppFooPriv.apk")
 }
 
 func TestApexWithAppImportsPrefer(t *testing.T) {
@@ -5818,7 +5787,7 @@
 	}))
 
 	ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
-		"app/AppFoo@TEST.BUILD_ID/AppFooPrebuilt.apk",
+		"app/AppFoo@__APEX_VERSION_PLACEHOLDER__/AppFooPrebuilt.apk",
 	})
 }
 
@@ -5851,7 +5820,7 @@
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
-	ensureContains(t, copyCmds, "image.apex/app/TesterHelpAppFoo@TEST.BUILD_ID/TesterHelpAppFoo.apk")
+	ensureContains(t, copyCmds, "image.apex/app/TesterHelpAppFoo@__APEX_VERSION_PLACEHOLDER__/TesterHelpAppFoo.apk")
 }
 
 func TestApexPropertiesShouldBeDefaultable(t *testing.T) {
@@ -6294,8 +6263,8 @@
 	apexRule := module.Rule("apexRule")
 	copyCmds := apexRule.Args["copy_commands"]
 
-	ensureNotContains(t, copyCmds, "image.apex/app/app@TEST.BUILD_ID/app.apk")
-	ensureContains(t, copyCmds, "image.apex/app/override_app@TEST.BUILD_ID/override_app.apk")
+	ensureNotContains(t, copyCmds, "image.apex/app/app@__APEX_VERSION_PLACEHOLDER__/app.apk")
+	ensureContains(t, copyCmds, "image.apex/app/override_app@__APEX_VERSION_PLACEHOLDER__/override_app.apk")
 
 	ensureNotContains(t, copyCmds, "image.apex/etc/bpf/bpf.o")
 	ensureContains(t, copyCmds, "image.apex/etc/bpf/override_bpf.o")
@@ -7199,7 +7168,7 @@
 	content := bundleConfigRule.Args["content"]
 
 	ensureContains(t, content, `"compression":{"uncompressed_glob":["apex_payload.img","apex_manifest.*"]}`)
-	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo@TEST.BUILD_ID/AppFoo.apk"}]}`)
+	ensureContains(t, content, `"apex_config":{"apex_embedded_apk_config":[{"package_name":"com.android.foo","path":"app/AppFoo@__APEX_VERSION_PLACEHOLDER__/AppFoo.apk"}]}`)
 }
 
 func TestAppSetBundle(t *testing.T) {
@@ -7230,9 +7199,9 @@
 	if len(copyCmds) != 3 {
 		t.Fatalf("Expected 3 commands, got %d in:\n%s", len(copyCmds), s)
 	}
-	ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet@TEST.BUILD_ID$")
-	ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet@TEST.BUILD_ID$")
-	ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet@TEST.BUILD_ID .*/AppSet.zip$")
+	ensureMatches(t, copyCmds[0], "^rm -rf .*/app/AppSet@__APEX_VERSION_PLACEHOLDER__$")
+	ensureMatches(t, copyCmds[1], "^mkdir -p .*/app/AppSet@__APEX_VERSION_PLACEHOLDER__$")
+	ensureMatches(t, copyCmds[2], "^unzip .*-d .*/app/AppSet@__APEX_VERSION_PLACEHOLDER__ .*/AppSet.zip$")
 }
 
 func TestAppSetBundlePrebuilt(t *testing.T) {
diff --git a/apex/builder.go b/apex/builder.go
index abbf8ad..d4765d0 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -107,14 +107,16 @@
 			`--canned_fs_config ${canned_fs_config} ` +
 			`--include_build_info ` +
 			`--payload_type image ` +
-			`--key ${key} ${opt_flags} ${image_dir} ${out} `,
+			`--key ${key} ` +
+			`--apex_version_placeholder ${apex_version_placeholder} ` +
+			`${opt_flags} ${image_dir} ${out} `,
 		CommandDeps: []string{"${apexer}", "${avbtool}", "${e2fsdroid}", "${merge_zips}",
 			"${mke2fs}", "${resize2fs}", "${sefcontext_compile}", "${make_f2fs}", "${sload_f2fs}", "${make_erofs}",
 			"${soong_zip}", "${zipalign}", "${aapt2}", "prebuilts/sdk/current/public/android.jar"},
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "APEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type")
+	}, "tool_path", "image_dir", "copy_commands", "file_contexts", "canned_fs_config", "key", "opt_flags", "manifest", "payload_fs_type", "apex_version_placeholder")
 
 	zipApexRule = pctx.StaticRule("zipApexRule", blueprint.RuleParams{
 		Command: `rm -rf ${image_dir} && mkdir -p ${image_dir} && ` +
@@ -122,12 +124,13 @@
 			`APEXER_TOOL_PATH=${tool_path} ` +
 			`${apexer} --force --manifest ${manifest} ` +
 			`--payload_type zip ` +
+			`--apex_version_placeholder ${apex_version_placeholder} ` +
 			`${image_dir} ${out} `,
 		CommandDeps:    []string{"${apexer}", "${merge_zips}", "${soong_zip}", "${zipalign}", "${aapt2}"},
 		Rspfile:        "${out}.copy_commands",
 		RspfileContent: "${copy_commands}",
 		Description:    "ZipAPEX ${image_dir} => ${out}",
-	}, "tool_path", "image_dir", "copy_commands", "manifest")
+	}, "tool_path", "image_dir", "copy_commands", "manifest", "apex_version_placeholder")
 
 	apexProtoConvertRule = pctx.AndroidStaticRule("apexProtoConvertRule",
 		blueprint.RuleParams{
@@ -658,14 +661,15 @@
 			Output:      unsignedOutputFile,
 			Description: "apex (" + apexType.name() + ")",
 			Args: map[string]string{
-				"tool_path":        outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":        imageDir.String(),
-				"copy_commands":    strings.Join(copyCommands, " && "),
-				"manifest":         a.manifestPbOut.String(),
-				"file_contexts":    fileContexts.String(),
-				"canned_fs_config": cannedFsConfig.String(),
-				"key":              a.privateKeyFile.String(),
-				"opt_flags":        strings.Join(optFlags, " "),
+				"tool_path":                outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":                imageDir.String(),
+				"copy_commands":            strings.Join(copyCommands, " && "),
+				"manifest":                 a.manifestPbOut.String(),
+				"file_contexts":            fileContexts.String(),
+				"canned_fs_config":         cannedFsConfig.String(),
+				"key":                      a.privateKeyFile.String(),
+				"opt_flags":                strings.Join(optFlags, " "),
+				"apex_version_placeholder": APEX_VERSION_PLACEHOLDER,
 			},
 		})
 
@@ -757,10 +761,11 @@
 			Output:      unsignedOutputFile,
 			Description: "apex (" + apexType.name() + ")",
 			Args: map[string]string{
-				"tool_path":     outHostBinDir + ":" + prebuiltSdkToolsBinDir,
-				"image_dir":     imageDir.String(),
-				"copy_commands": strings.Join(copyCommands, " && "),
-				"manifest":      a.manifestPbOut.String(),
+				"tool_path":                outHostBinDir + ":" + prebuiltSdkToolsBinDir,
+				"image_dir":                imageDir.String(),
+				"copy_commands":            strings.Join(copyCommands, " && "),
+				"manifest":                 a.manifestPbOut.String(),
+				"apex_version_placeholder": APEX_VERSION_PLACEHOLDER,
 			},
 		})
 	}
diff --git a/bp2build/cc_library_shared_conversion_test.go b/bp2build/cc_library_shared_conversion_test.go
index 22c9dfe..7c2c100 100644
--- a/bp2build/cc_library_shared_conversion_test.go
+++ b/bp2build/cc_library_shared_conversion_test.go
@@ -176,8 +176,8 @@
         ":whole_static_lib_1",
         ":whole_static_lib_2",
     ]`,
-        "sdk_version": `"current"`,
-        "min_sdk_version": `"29"`,
+				"sdk_version":     `"current"`,
+				"min_sdk_version": `"29"`,
 			}),
 		},
 	})
@@ -496,3 +496,27 @@
 	},
 	)
 }
+
+func TestCcLibrarySharedSystemSharedLibsSharedEmpty(t *testing.T) {
+	runCcLibrarySharedTestCase(t, bp2buildTestCase{
+		description:                "cc_library_shared system_shared_libs empty shared default",
+		moduleTypeUnderTest:        "cc_library_shared",
+		moduleTypeUnderTestFactory: cc.LibrarySharedFactory,
+		blueprint: soongCcLibrarySharedPreamble + `
+cc_defaults {
+    name: "empty_defaults",
+    shared: {
+        system_shared_libs: [],
+    },
+    include_build_directory: false,
+}
+cc_library_shared {
+    name: "empty",
+    defaults: ["empty_defaults"],
+}
+`,
+		expectedBazelTargets: []string{makeBazelTarget("cc_library_shared", "empty", attrNameToString{
+			"system_dynamic_deps": "[]",
+		})},
+	})
+}
diff --git a/build_test.bash b/build_test.bash
index 1dc6660..8b91e2c 100755
--- a/build_test.bash
+++ b/build_test.bash
@@ -25,7 +25,8 @@
 
 # Products that are broken or otherwise don't work with multiproduct_kati
 SKIPPED_PRODUCTS=(
-    # Both of these products are for soong-only builds, and will fail the kati stage.
+    # These products are for soong-only builds, and will fail the kati stage.
+    linux_bionic
     mainline_sdk
     ndk
 )
diff --git a/cc/Android.bp b/cc/Android.bp
index 9103a48..b105e7c 100644
--- a/cc/Android.bp
+++ b/cc/Android.bp
@@ -100,6 +100,7 @@
         "proto_test.go",
         "sanitize_test.go",
         "test_data_test.go",
+        "tidy_test.go",
         "vendor_public_library_test.go",
         "vendor_snapshot_test.go",
     ],
diff --git a/cc/OWNERS b/cc/OWNERS
index a438b15..ffbf14a 100644
--- a/cc/OWNERS
+++ b/cc/OWNERS
@@ -1,4 +1,4 @@
 per-file ndk_*.go = danalbert@google.com
-per-file tidy.go = srhines@google.com, chh@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/config/global.go b/cc/config/global.go
index 65bfbf0..3caf327 100644
--- a/cc/config/global.go
+++ b/cc/config/global.go
@@ -286,8 +286,8 @@
 
 	// prebuilts/clang default settings.
 	ClangDefaultBase         = "prebuilts/clang/host"
-	ClangDefaultVersion      = "clang-r450784c"
-	ClangDefaultShortVersion = "14.0.5"
+	ClangDefaultVersion      = "clang-r450784d"
+	ClangDefaultShortVersion = "14.0.6"
 
 	// Directories with warnings from Android.bp files.
 	WarningAllowedProjects = []string{
diff --git a/cc/tidy.go b/cc/tidy.go
index 750e9de..03e967d 100644
--- a/cc/tidy.go
+++ b/cc/tidy.go
@@ -76,9 +76,10 @@
 	// the global WITH_TIDY or module 'tidy' property is true.
 	flags.Tidy = true
 
-	// If explicitly enabled, by global default or local tidy property,
+	// If explicitly enabled, by global WITH_TIDY or local tidy:true property,
 	// set flags.NeedTidyFiles to make this module depend on .tidy files.
-	if ctx.Config().ClangTidy() || Bool(tidy.Properties.Tidy) {
+	// Note that locally set tidy:true is ignored if ALLOW_LOCAL_TIDY_TRUE is not set to true.
+	if ctx.Config().IsEnvTrue("WITH_TIDY") || (ctx.Config().IsEnvTrue("ALLOW_LOCAL_TIDY_TRUE") && Bool(tidy.Properties.Tidy)) {
 		flags.NeedTidyFiles = true
 	}
 
diff --git a/cc/tidy_test.go b/cc/tidy_test.go
new file mode 100644
index 0000000..339b302
--- /dev/null
+++ b/cc/tidy_test.go
@@ -0,0 +1,98 @@
+// 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 cc
+
+import (
+	"fmt"
+	"testing"
+
+	"android/soong/android"
+)
+
+func TestWithTidy(t *testing.T) {
+	// When WITH_TIDY=1 or (ALLOW_LOCAL_TIDY_TRUE=1 and local tidy:true)
+	// a C++ library should depend on .tidy files.
+	testCases := []struct {
+		withTidy, allowLocalTidyTrue string // "_" means undefined
+		needTidyFile                 []bool // for {libfoo_0, libfoo_1} and {libbar_0, libbar_1}
+	}{
+		{"_", "_", []bool{false, false, false}},
+		{"_", "0", []bool{false, false, false}},
+		{"_", "1", []bool{false, true, false}},
+		{"_", "true", []bool{false, true, false}},
+		{"0", "_", []bool{false, false, false}},
+		{"0", "1", []bool{false, true, false}},
+		{"1", "_", []bool{true, true, false}},
+		{"1", "false", []bool{true, true, false}},
+		{"1", "1", []bool{true, true, false}},
+		{"true", "_", []bool{true, true, false}},
+	}
+	bp := `
+		cc_library_shared {
+			name: "libfoo_0", // depends on .tidy if WITH_TIDY=1
+			srcs: ["foo.c"],
+		}
+		cc_library_shared { // depends on .tidy if WITH_TIDY=1 or ALLOW_LOCAL_TIDY_TRUE=1
+			name: "libfoo_1",
+			srcs: ["foo.c"],
+			tidy: true,
+		}
+		cc_library_shared { // no .tidy
+			name: "libfoo_2",
+			srcs: ["foo.c"],
+			tidy: false,
+		}
+		cc_library_static {
+			name: "libbar_0", // depends on .tidy if WITH_TIDY=1
+			srcs: ["bar.c"],
+		}
+		cc_library_static { // depends on .tidy if WITH_TIDY=1 or ALLOW_LOCAL_TIDY_TRUE=1
+			name: "libbar_1",
+			srcs: ["bar.c"],
+			tidy: true,
+		}
+		cc_library_static { // no .tidy
+			name: "libbar_2",
+			srcs: ["bar.c"],
+			tidy: false,
+		}`
+	for index, test := range testCases {
+		testName := fmt.Sprintf("case%d,%v,%v", index, test.withTidy, test.allowLocalTidyTrue)
+		t.Run(testName, func(t *testing.T) {
+			testEnv := map[string]string{}
+			if test.withTidy != "_" {
+				testEnv["WITH_TIDY"] = test.withTidy
+			}
+			if test.allowLocalTidyTrue != "_" {
+				testEnv["ALLOW_LOCAL_TIDY_TRUE"] = test.allowLocalTidyTrue
+			}
+			ctx := android.GroupFixturePreparers(prepareForCcTest, android.FixtureMergeEnv(testEnv)).RunTestWithBp(t, bp)
+			for n := 0; n < 3; n++ {
+				checkLibraryRule := func(foo, variant, ruleName string) {
+					libName := fmt.Sprintf("lib%s_%d", foo, n)
+					tidyFile := "out/soong/.intermediates/" + libName + "/" + variant + "/obj/" + foo + ".tidy"
+					depFiles := ctx.ModuleForTests(libName, variant).Rule(ruleName).Validations.Strings()
+					if test.needTidyFile[n] {
+						android.AssertStringListContains(t, libName+" needs .tidy file", depFiles, tidyFile)
+					} else {
+						android.AssertStringListDoesNotContain(t, libName+" does not need .tidy file", depFiles, tidyFile)
+					}
+				}
+				checkLibraryRule("foo", "android_arm64_armv8-a_shared", "ld")
+				checkLibraryRule("bar", "android_arm64_armv8-a_static", "ar")
+			}
+		})
+	}
+}
diff --git a/java/android_manifest.go b/java/android_manifest.go
index 7772b70..3fa3520 100644
--- a/java/android_manifest.go
+++ b/java/android_manifest.go
@@ -82,8 +82,8 @@
 		if minSdkVersion.FinalOrFutureInt() >= 23 {
 			args = append(args, fmt.Sprintf("--extract-native-libs=%v", !params.UseEmbeddedNativeLibs))
 		} else if params.UseEmbeddedNativeLibs {
-			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%d doesn't support it",
-				minSdkVersion)
+			ctx.ModuleErrorf("module attempted to store uncompressed native libraries, but minSdkVersion=%s doesn't support it",
+				minSdkVersion.String())
 		}
 	}
 
diff --git a/java/base.go b/java/base.go
index b925350..a076718 100644
--- a/java/base.go
+++ b/java/base.go
@@ -1481,11 +1481,11 @@
 	}
 
 	if ctx.Device() {
-		lintSDKVersionString := func(sdkSpec android.SdkSpec) string {
+		lintSDKVersion := func(sdkSpec android.SdkSpec) android.ApiLevel {
 			if v := sdkSpec.ApiLevel; !v.IsPreview() {
-				return v.String()
+				return v
 			} else {
-				return ctx.Config().DefaultAppTargetSdk(ctx).String()
+				return ctx.Config().DefaultAppTargetSdk(ctx)
 			}
 		}
 
@@ -1494,9 +1494,9 @@
 		j.linter.srcJars = srcJars
 		j.linter.classpath = append(append(android.Paths(nil), flags.bootClasspath...), flags.classpath...)
 		j.linter.classes = j.implementationJarFile
-		j.linter.minSdkVersion = lintSDKVersionString(j.MinSdkVersion(ctx))
-		j.linter.targetSdkVersion = lintSDKVersionString(j.TargetSdkVersion(ctx))
-		j.linter.compileSdkVersion = lintSDKVersionString(j.SdkVersion(ctx))
+		j.linter.minSdkVersion = lintSDKVersion(j.MinSdkVersion(ctx))
+		j.linter.targetSdkVersion = lintSDKVersion(j.TargetSdkVersion(ctx))
+		j.linter.compileSdkVersion = lintSDKVersion(j.SdkVersion(ctx))
 		j.linter.compileSdkKind = j.SdkVersion(ctx).Kind
 		j.linter.javaLanguageLevel = flags.javaVersion.String()
 		j.linter.kotlinLanguageLevel = "1.3"
diff --git a/java/lint.go b/java/lint.go
index e97c9c2..426a2af 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -75,9 +75,9 @@
 	extraLintCheckJars      android.Paths
 	test                    bool
 	library                 bool
-	minSdkVersion           string
-	targetSdkVersion        string
-	compileSdkVersion       string
+	minSdkVersion           android.ApiLevel
+	targetSdkVersion        android.ApiLevel
+	compileSdkVersion       android.ApiLevel
 	compileSdkKind          android.SdkKind
 	javaLanguageLevel       string
 	kotlinLanguageLevel     string
@@ -300,7 +300,7 @@
 		Text(`echo "<manifest xmlns:android='http://schemas.android.com/apk/res/android'" &&`).
 		Text(`echo "    android:versionCode='1' android:versionName='1' >" &&`).
 		Textf(`echo "  <uses-sdk android:minSdkVersion='%s' android:targetSdkVersion='%s'/>" &&`,
-			l.minSdkVersion, l.targetSdkVersion).
+			l.minSdkVersion.String(), l.targetSdkVersion.String()).
 		Text(`echo "</manifest>"`).
 		Text(") >").Output(manifestPath)
 
@@ -325,7 +325,7 @@
 		return
 	}
 
-	if l.minSdkVersion != l.compileSdkVersion {
+	if l.minSdkVersion.CompareTo(l.compileSdkVersion) == -1 {
 		l.extraMainlineLintErrors = append(l.extraMainlineLintErrors, updatabilityChecks...)
 		_, filtered := android.FilterList(l.properties.Lint.Warning_checks, updatabilityChecks)
 		if len(filtered) != 0 {
@@ -427,7 +427,7 @@
 		FlagWithOutput("--html ", html).
 		FlagWithOutput("--text ", text).
 		FlagWithOutput("--xml ", xml).
-		FlagWithArg("--compile-sdk-version ", l.compileSdkVersion).
+		FlagWithArg("--compile-sdk-version ", l.compileSdkVersion.String()).
 		FlagWithArg("--java-language-level ", l.javaLanguageLevel).
 		FlagWithArg("--kotlin-language-level ", l.kotlinLanguageLevel).
 		FlagWithArg("--url ", fmt.Sprintf(".=.,%s=out", android.PathForOutput(ctx).String())).
diff --git a/java/lint_defaults.txt b/java/lint_defaults.txt
index 4bc0c5f..1eee354 100644
--- a/java/lint_defaults.txt
+++ b/java/lint_defaults.txt
@@ -28,6 +28,11 @@
 --disable_check SuspiciousImport
 --disable_check UnusedResources
 --disable_check ViewConstructor
+# Disable NewApi checks for the platform since platform is the one that implements
+# the API. This prevents noisy lint warnings like b/228956345#1
+# NewApi checks will continue to be enforced for apex deps since
+# lint.strict_updatability_linting will be true for those Soong modules
+--disable_check NewApi
 
 # Downgrade existing errors to warnings
 --warning_check AppCompatResource                  # 55 occurences in 10 modules
@@ -66,7 +71,6 @@
 --warning_check MissingTvBanner                    # 3 occurences in 3 modules
 --warning_check NamespaceTypo                      # 3 occurences in 3 modules
 --warning_check NetworkSecurityConfig              # 46 occurences in 12 modules
---warning_check NewApi                             # 1996 occurences in 122 modules
 --warning_check NotSibling                         # 15 occurences in 10 modules
 --warning_check ObjectAnimatorBinding              # 14 occurences in 5 modules
 --warning_check OnClick                            # 49 occurences in 21 modules
diff --git a/rust/config/global.go b/rust/config/global.go
index 2d5fa99..6bfa9cf 100644
--- a/rust/config/global.go
+++ b/rust/config/global.go
@@ -24,7 +24,7 @@
 var pctx = android.NewPackageContext("android/soong/rust/config")
 
 var (
-	RustDefaultVersion = "1.59.0"
+	RustDefaultVersion = "1.60.0"
 	RustDefaultBase    = "prebuilts/rust/"
 	DefaultEdition     = "2021"
 	Stdlibs            = []string{