Merge "Prevent concurrent read/writes to a map" into main
diff --git a/android/allowlists/allowlists.go b/android/allowlists/allowlists.go
index 43859ee..9916451 100644
--- a/android/allowlists/allowlists.go
+++ b/android/allowlists/allowlists.go
@@ -310,6 +310,7 @@
 		"packages/modules/StatsD/lib/libstatssocket":         Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb":                               Bp2BuildDefaultTrue,
 		"packages/modules/adb/apex":                          Bp2BuildDefaultTrue,
+		"packages/modules/adb/fastdeploy":                    Bp2BuildDefaultTrue,
 		"packages/modules/adb/crypto":                        Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/libs":                          Bp2BuildDefaultTrueRecursively,
 		"packages/modules/adb/pairing_auth":                  Bp2BuildDefaultTrueRecursively,
@@ -1612,6 +1613,7 @@
 		"permissive_mte_test",
 		"ICU4CTestRunner",
 		"DeviceLongPollingStubTest",
+		"FastDeployHostTests",
 
 		"libprotobuf-full-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
 		"libprotobuf-lite-test", // TODO(b/246997908): cannot convert proto_libraries which implicitly include other srcs in the same directory
diff --git a/android/api_levels.go b/android/api_levels.go
index 44c8640..3f538c0 100644
--- a/android/api_levels.go
+++ b/android/api_levels.go
@@ -19,6 +19,7 @@
 	"encoding/json"
 	"fmt"
 	"strconv"
+	"strings"
 )
 
 func init() {
@@ -237,6 +238,14 @@
 	}
 }
 
+func uncheckedFinalIncrementalApiLevel(num int, increment int) ApiLevel {
+	return ApiLevel{
+		value:     strconv.Itoa(num) + "." + strconv.Itoa(increment),
+		number:    num,
+		isPreview: false,
+	}
+}
+
 var NoneApiLevel = ApiLevel{
 	value: "(no version)",
 	// Not 0 because we don't want this to compare equal with the first preview.
@@ -371,6 +380,22 @@
 		return FutureApiLevel
 	}
 
+	if strings.Contains(raw, ".") {
+		// Check prebuilt incremental API format MM.m for major (API level) and minor (incremental) revisions
+		parts := strings.Split(raw, ".")
+		if len(parts) != 2 {
+			panic(fmt.Errorf("Found unexpected version '%s' for incremental API - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", raw))
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			panic(fmt.Errorf("Unable to read version number for incremental api '%s'", raw))
+		}
+
+		apiLevel := uncheckedFinalIncrementalApiLevel(sdk, qpr)
+		return apiLevel
+	}
+
 	asInt, err := strconv.Atoi(raw)
 	if err != nil {
 		panic(fmt.Errorf("%q could not be parsed as an integer and is not a recognized codename", raw))
diff --git a/android/config.go b/android/config.go
index 3e7bb14..0b15c79 100644
--- a/android/config.go
+++ b/android/config.go
@@ -2081,3 +2081,7 @@
 func (c *config) GetApiLibraries() map[string]struct{} {
 	return c.apiLibraries
 }
+
+func (c *deviceConfig) CheckVendorSeappViolations() bool {
+	return Bool(c.config.productVariables.CheckVendorSeappViolations)
+}
diff --git a/android/mutator.go b/android/mutator.go
index 6bcac93..41477b8 100644
--- a/android/mutator.go
+++ b/android/mutator.go
@@ -231,6 +231,7 @@
 	BazelConversionPathContext
 
 	CreateBazelTargetModule(bazel.BazelTargetModuleProperties, CommonAttributes, interface{})
+	CreateBazelTargetModuleWithRestrictions(bazel.BazelTargetModuleProperties, CommonAttributes, interface{}, bazel.BoolAttribute)
 }
 
 // PreArchBp2BuildMutators adds mutators to be register for converting Android Blueprint modules
diff --git a/android/proto.go b/android/proto.go
index a44daf0..3c4b4c7 100644
--- a/android/proto.go
+++ b/android/proto.go
@@ -331,7 +331,8 @@
 				Label: l,
 			})
 		}
-		protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, protoIncludeDirs)
+		// Partitioning by packages can create dupes of protoIncludeDirs, so dedupe it first.
+		protoLibrariesInIncludeDir := createProtoLibraryTargetsForIncludeDirs(ctx, SortedUniqueStrings(protoIncludeDirs))
 		transitiveProtoLibraries.Append(protoLibrariesInIncludeDir)
 	}
 
@@ -406,7 +407,13 @@
 			if rel != "." {
 				attrs.Import_prefix = proptools.StringPtr(rel)
 			}
-			ctx.CreateBazelTargetModule(
+
+			// If a specific directory is listed in proto.include_dirs of two separate modules (one host-specific and another device-specific),
+			// we do not want to create the proto_library with target_compatible_with of the first visited of these two modules
+			// As a workarounds, delete `target_compatible_with`
+			alwaysEnabled := bazel.BoolAttribute{}
+			alwaysEnabled.Value = proptools.BoolPtr(true)
+			ctx.CreateBazelTargetModuleWithRestrictions(
 				bazel.BazelTargetModuleProperties{Rule_class: "proto_library"},
 				CommonAttributes{
 					Name: label,
@@ -416,6 +423,7 @@
 					Tags: bazel.MakeStringListAttribute([]string{"manual"}),
 				},
 				&attrs,
+				alwaysEnabled,
 			)
 		}
 	}
diff --git a/android/variable.go b/android/variable.go
index ca9a221..8805fe5 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -486,6 +486,8 @@
 	ReleaseAconfigFlagDefaultPermission string `json:",omitempty"`
 
 	KeepVndk *bool `json:",omitempty"`
+
+	CheckVendorSeappViolations *bool `json:",omitempty"`
 }
 
 func boolPtr(v bool) *bool {
diff --git a/bp2build/cc_library_conversion_test.go b/bp2build/cc_library_conversion_test.go
index 6501217..02ed57a 100644
--- a/bp2build/cc_library_conversion_test.go
+++ b/bp2build/cc_library_conversion_test.go
@@ -5120,7 +5120,7 @@
 	// bar dir
 	tc.Dir = "bar"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["bar.proto"]`,
 			"strip_import_prefix": `""`,
 			"tags":                `["manual"]`,
@@ -5131,7 +5131,7 @@
 	// bar/baz dir
 	tc.Dir = "bar/baz"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "bar.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["//bar/baz:baz.proto"]`,
 			"strip_import_prefix": `""`,
 			"import_prefix":       `"baz"`,
@@ -5141,6 +5141,52 @@
 	runCcLibraryTestCase(t, tc)
 }
 
+func TestProtoIncludeDirsWithSrcsInMultiplePackages(t *testing.T) {
+	tc := Bp2buildTestCase{
+		Description:                "cc_library has srcs in multiple bazel packages and uses proto.include_dirs",
+		ModuleTypeUnderTest:        "cc_library",
+		ModuleTypeUnderTestFactory: cc.LibraryFactory,
+		Blueprint: `
+cc_library_static {
+	name: "foo",
+	srcs: [
+	   "foo.proto",
+	   "bar/bar.proto",
+	],
+	proto: {
+		include_dirs: ["baz"],
+	}
+}
+` + simpleModuleDoNotConvertBp2build("cc_library", "libprotobuf-cpp-lite"),
+		Filesystem: map[string]string{
+			"bar/Android.bp": "", // package boundary
+			"baz/Android.bp": "",
+			"baz/baz.proto":  "",
+		},
+	}
+
+	tc.ExpectedBazelTargets = []string{
+		MakeBazelTarget("cc_library_static", "foo", AttrNameToString{
+			"local_includes":                    `["."]`,
+			"deps":                              `[":libprotobuf-cpp-lite"]`,
+			"implementation_whole_archive_deps": `[":foo_cc_proto_lite"]`,
+		}),
+		MakeBazelTarget("proto_library", "foo_proto", AttrNameToString{
+			"srcs": `["foo.proto"]`,
+			"tags": `["manual"]`,
+		}),
+		MakeBazelTarget("cc_lite_proto_library", "foo_cc_proto_lite", AttrNameToString{
+			"deps": `[
+        ":foo_proto",
+        "//bar:foo_proto",
+    ]`,
+			"transitive_deps": `["//baz:baz.include_dir_bp2build_generated_proto"]`,
+		}),
+	}
+	runCcLibraryTestCase(t, tc)
+
+}
+
 func TestProtoLocalIncludeDirs(t *testing.T) {
 	tc := Bp2buildTestCase{
 		Description:                "cc_library depends on .proto files using proto.local_include_dirs",
@@ -5187,7 +5233,7 @@
 	// foo/foo_subdir
 	tc.Dir = "foo/foo_subdir"
 	tc.ExpectedBazelTargets = []string{
-		MakeBazelTarget("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{
+		MakeBazelTargetNoRestrictions("proto_library", "foo.foo_subdir.include_dir_bp2build_generated_proto", AttrNameToString{
 			"srcs":                `["foo_subdir.proto"]`,
 			"strip_import_prefix": `""`,
 			"tags":                `["manual"]`,
diff --git a/java/prebuilt_apis.go b/java/prebuilt_apis.go
index 044802e..99cb99b 100644
--- a/java/prebuilt_apis.go
+++ b/java/prebuilt_apis.go
@@ -55,6 +55,11 @@
 
 	// If set to true, compile dex for java_import modules. Defaults to false.
 	Imports_compile_dex *bool
+
+	// If set to true, allow incremental platform API of the form MM.m where MM is the major release
+	// version corresponding to the API level/SDK_INT and m is an incremental release version
+	// (e.g. API changes associated with QPR). Defaults to false.
+	Allow_incremental_platform_api *bool
 }
 
 type prebuiltApis struct {
@@ -69,6 +74,8 @@
 // parsePrebuiltPath parses the relevant variables out of a variety of paths, e.g.
 // <version>/<scope>/<module>.jar
 // <version>/<scope>/api/<module>.txt
+// *Note when using incremental platform API, <version> may be of the form MM.m where MM is the
+// API level and m is an incremental release, otherwise <version> is a single integer corresponding to the API level only.
 // extensions/<version>/<scope>/<module>.jar
 // extensions/<version>/<scope>/api/<module>.txt
 func parsePrebuiltPath(ctx android.LoadHookContext, p string) (module string, version string, scope string) {
@@ -90,8 +97,25 @@
 }
 
 // parseFinalizedPrebuiltPath is like parsePrebuiltPath, but verifies the version is numeric (a finalized version).
-func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string) (module string, version int, scope string) {
+func parseFinalizedPrebuiltPath(ctx android.LoadHookContext, p string, allowIncremental bool) (module string, version int, release int, scope string) {
 	module, v, scope := parsePrebuiltPath(ctx, p)
+	if allowIncremental {
+		parts := strings.Split(v, ".")
+		if len(parts) != 2 {
+			ctx.ModuleErrorf("Found unexpected version '%v' for incremental prebuilts - expect MM.m format for incremental API with both major (MM) an minor (m) revision.", v)
+			return
+		}
+		sdk, sdk_err := strconv.Atoi(parts[0])
+		qpr, qpr_err := strconv.Atoi(parts[1])
+		if sdk_err != nil || qpr_err != nil {
+			ctx.ModuleErrorf("Unable to read version number for incremental prebuilt api '%v'", v)
+			return
+		}
+		version = sdk
+		release = qpr
+		return
+	}
+	release = 0
 	version, err := strconv.Atoi(v)
 	if err != nil {
 		ctx.ModuleErrorf("Found finalized API files in non-numeric dir '%v'", v)
@@ -268,29 +292,35 @@
 	}
 
 	// Create modules for all (<module>, <scope, <version>) triplets,
+	allowIncremental := proptools.BoolDefault(p.properties.Allow_incremental_platform_api, false)
 	for _, f := range apiLevelFiles {
-		module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
-		createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
+		if allowIncremental {
+			incrementalVersion := strconv.Itoa(version) + "." + strconv.Itoa(release)
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, incrementalVersion), f)
+		} else {
+			createApiModule(mctx, PrebuiltApiModuleName(module, scope, strconv.Itoa(version)), f)
+		}
 	}
 
 	// Figure out the latest version of each module/scope
 	type latestApiInfo struct {
 		module, scope, path string
-		version             int
+		version, release    int
 		isExtensionApiFile  bool
 	}
 
 	getLatest := func(files []string, isExtensionApiFile bool) map[string]latestApiInfo {
 		m := make(map[string]latestApiInfo)
 		for _, f := range files {
-			module, version, scope := parseFinalizedPrebuiltPath(mctx, f)
+			module, version, release, scope := parseFinalizedPrebuiltPath(mctx, f, allowIncremental)
 			if strings.HasSuffix(module, "incompatibilities") {
 				continue
 			}
 			key := module + "." + scope
 			info, exists := m[key]
-			if !exists || version > info.version {
-				m[key] = latestApiInfo{module, scope, f, version, isExtensionApiFile}
+			if !exists || version > info.version || (version == info.version && release > info.release) {
+				m[key] = latestApiInfo{module, scope, f, version, release, isExtensionApiFile}
 			}
 		}
 		return m
diff --git a/java/prebuilt_apis_test.go b/java/prebuilt_apis_test.go
index 2b84353..b6fb2c6 100644
--- a/java/prebuilt_apis_test.go
+++ b/java/prebuilt_apis_test.go
@@ -99,3 +99,26 @@
 	android.AssertStringEquals(t, "Expected latest bar = extension level 2", "prebuilts/sdk/extensions/2/public/api/bar.txt", bar_input)
 	android.AssertStringEquals(t, "Expected latest baz = api level 32", "prebuilts/sdk/32/public/api/baz.txt", baz_input)
 }
+
+func TestPrebuiltApis_WithIncrementalApi(t *testing.T) {
+	runTestWithIncrementalApi := func() (foo_input, bar_input, baz_input string) {
+		result := android.GroupFixturePreparers(
+			prepareForJavaTest,
+			FixtureWithPrebuiltIncrementalApis(map[string][]string{
+				"33.0":    {"foo"},
+				"33.1":    {"foo", "bar", "baz"},
+				"33.2":    {"foo", "bar"},
+				"current": {"foo", "bar"},
+			}),
+		).RunTest(t)
+		foo_input = result.ModuleForTests("foo.api.public.latest", "").Rule("generator").Implicits[0].String()
+		bar_input = result.ModuleForTests("bar.api.public.latest", "").Rule("generator").Implicits[0].String()
+		baz_input = result.ModuleForTests("baz.api.public.latest", "").Rule("generator").Implicits[0].String()
+		return
+	}
+	// 33.1 is the latest for baz, 33.2 is the latest for both foo & bar
+	foo_input, bar_input, baz_input := runTestWithIncrementalApi()
+	android.AssertStringEquals(t, "Expected latest foo = api level 33.2", "prebuilts/sdk/33.2/public/api/foo.txt", foo_input)
+	android.AssertStringEquals(t, "Expected latest bar = api level 33.2", "prebuilts/sdk/33.2/public/api/bar.txt", bar_input)
+	android.AssertStringEquals(t, "Expected latest baz = api level 33.1", "prebuilts/sdk/33.1/public/api/baz.txt", baz_input)
+}
diff --git a/java/testing.go b/java/testing.go
index 7f6ee57..f2bcccf 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -225,6 +225,29 @@
 	)
 }
 
+func FixtureWithPrebuiltIncrementalApis(apiLevel2Modules map[string][]string) android.FixturePreparer {
+	mockFS := android.MockFS{}
+	path := "prebuilts/sdk/Android.bp"
+
+	bp := fmt.Sprintf(`
+			prebuilt_apis {
+				name: "sdk",
+				api_dirs: ["%s"],
+				allow_incremental_platform_api: true,
+				imports_sdk_version: "none",
+				imports_compile_dex: true,
+			}
+		`, strings.Join(android.SortedKeys(apiLevel2Modules), `", "`))
+
+	for release, modules := range apiLevel2Modules {
+		mockFS.Merge(prebuiltApisFilesForModules([]string{release}, modules))
+	}
+	return android.GroupFixturePreparers(
+		android.FixtureAddTextFile(path, bp),
+		android.FixtureMergeMockFs(mockFS),
+	)
+}
+
 func prebuiltApisFilesForModules(apiLevels []string, modules []string) map[string][]byte {
 	libs := append([]string{"android"}, modules...)