Create api_domain module type and its bp2build converter

This module does not have any build actions in Soong yet. It will be
converted to a Bazel target using bp2build, and API export will be run
on the generated Bazel target

Test: go test ./bp2build
Test: TH
Change-Id: I76df32bd9f23b60e746b2700af07668a2ed74844
diff --git a/android/Android.bp b/android/Android.bp
index e0ad58f..29a88f2 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -30,6 +30,7 @@
     srcs: [
         "androidmk.go",
         "apex.go",
+        "api_domain.go",
         "api_levels.go",
         "arch.go",
         "arch_list.go",
diff --git a/android/api_domain.go b/android/api_domain.go
new file mode 100644
index 0000000..a808e32
--- /dev/null
+++ b/android/api_domain.go
@@ -0,0 +1,100 @@
+// 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 android
+
+import (
+	"github.com/google/blueprint"
+
+	"android/soong/bazel"
+)
+
+func init() {
+	RegisterApiDomainBuildComponents(InitRegistrationContext)
+}
+
+func RegisterApiDomainBuildComponents(ctx RegistrationContext) {
+	ctx.RegisterModuleType("api_domain", ApiDomainFactory)
+}
+
+type apiDomain struct {
+	ModuleBase
+	BazelModuleBase
+
+	properties apiDomainProperties
+}
+
+type apiDomainProperties struct {
+	// cc library contributions (.h files/.map.txt) of this API domain
+	// This dependency is a no-op in Soong, but the corresponding Bazel target in the bp2build workspace will provide a `CcApiContributionInfo` provider
+	Cc_api_contributions []string
+}
+
+func ApiDomainFactory() Module {
+	m := &apiDomain{}
+	m.AddProperties(&m.properties)
+	InitAndroidArchModule(m, DeviceSupported, MultilibBoth)
+	InitBazelModule(m)
+	return m
+}
+
+func (a *apiDomain) DepsMutator(ctx BottomUpMutatorContext) {
+	for _, cc := range a.properties.Cc_api_contributions {
+		// Use FarVariationDependencies since the variants of api_domain is a subset of the variants of the dependency cc module
+		// Creating a dependency on the first variant is ok since this is a no-op in Soong
+		// The primary function of this dependency is to create a connected graph in the corresponding bp2build workspace
+		ctx.AddFarVariationDependencies([]blueprint.Variation{}, nil, cc)
+	}
+}
+
+// API domain does not have any builld actions yet
+func (a *apiDomain) GenerateAndroidBuildActions(ctx ModuleContext) {
+}
+
+const (
+	apiContributionSuffix = ".contribution"
+)
+
+// ApiContributionTargetName returns the name of the bp2build target (e.g. cc_api_contribution)  of contribution modules (e.g. ndk_library)
+// A suffix is necessary to prevent a name collision with the base target in the same bp2build bazel package
+func ApiContributionTargetName(moduleName string) string {
+	return moduleName + apiContributionSuffix
+}
+
+// For each contributing cc_library, format the name to its corresponding contribution bazel target in the bp2build workspace
+func contributionBazelAttributes(ctx TopDownMutatorContext, contributions []string) bazel.LabelListAttribute {
+	addSuffix := func(ctx BazelConversionPathContext, module blueprint.Module) string {
+		baseLabel := BazelModuleLabel(ctx, module)
+		return ApiContributionTargetName(baseLabel)
+	}
+	bazelLabels := BazelLabelForModuleDepsWithFn(ctx, contributions, addSuffix)
+	return bazel.MakeLabelListAttribute(bazelLabels)
+}
+
+type bazelApiDomainAttributes struct {
+	Cc_api_contributions bazel.LabelListAttribute
+}
+
+func (a *apiDomain) ConvertWithBp2build(ctx TopDownMutatorContext) {
+	props := bazel.BazelTargetModuleProperties{
+		Rule_class:        "api_domain",
+		Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
+	}
+	attrs := &bazelApiDomainAttributes{
+		Cc_api_contributions: contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
+	}
+	ctx.CreateBazelTargetModule(props, CommonAttributes{
+		Name: ctx.ModuleName(),
+	}, attrs)
+}
diff --git a/bp2build/api_domain_conversion_test.go b/bp2build/api_domain_conversion_test.go
new file mode 100644
index 0000000..fc9d1d5
--- /dev/null
+++ b/bp2build/api_domain_conversion_test.go
@@ -0,0 +1,68 @@
+// 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 bp2build
+
+import (
+	"testing"
+
+	"android/soong/android"
+	"android/soong/cc"
+)
+
+func registerApiDomainModuleTypes(ctx android.RegistrationContext) {
+	android.RegisterApiDomainBuildComponents(ctx)
+	cc.RegisterNdkModuleTypes(ctx)
+	cc.RegisterLibraryBuildComponents(ctx)
+}
+
+func TestApiDomainContributionsTest(t *testing.T) {
+	bp := `
+	api_domain {
+		name: "system",
+		cc_api_contributions: [
+			"libfoo.ndk",
+			"libbar",
+		],
+	}
+	`
+	fs := map[string]string{
+		"libfoo/Android.bp": `
+		ndk_library {
+			name: "libfoo",
+		}
+		`,
+		"libbar/Android.bp": `
+		cc_library {
+			name: "libbar",
+		}
+		`,
+	}
+	expectedBazelTarget := MakeBazelTargetNoRestrictions(
+		"api_domain",
+		"system",
+		AttrNameToString{
+			"cc_api_contributions": `[
+        "//libfoo:libfoo.ndk.contribution",
+        "//libbar:libbar.contribution",
+    ]`,
+			"target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+		},
+	)
+	RunBp2BuildTestCase(t, registerApiDomainModuleTypes, Bp2buildTestCase{
+		Blueprint:            bp,
+		ExpectedBazelTargets: []string{expectedBazelTarget},
+		Filesystem:           fs,
+	})
+}
diff --git a/cc/ndk_headers.go b/cc/ndk_headers.go
index 5e06948..08e2a39 100644
--- a/cc/ndk_headers.go
+++ b/cc/ndk_headers.go
@@ -147,16 +147,6 @@
 	}
 }
 
-const (
-	apiContributionSuffix = ".contribution"
-)
-
-// apiContributionTargetName returns the name of the cc_api(headers|contribution) bp2build target of ndk modules
-// A suffix is necessary to prevent a name collision with the base ndk_(library|header) target in the same bp2build bazel package
-func apiContributionTargetName(moduleName string) string {
-	return moduleName + apiContributionSuffix
-}
-
 // TODO(b/243196151): Populate `system` and `arch` metadata
 type bazelCcApiHeadersAttributes struct {
 	Hdrs        bazel.LabelListAttribute
@@ -179,7 +169,7 @@
 		Include_dir: include_dir,
 	}
 	ctx.CreateBazelTargetModule(props, android.CommonAttributes{
-		Name: apiContributionTargetName(ctx.ModuleName()),
+		Name: android.ApiContributionTargetName(ctx.ModuleName()),
 	}, attrs)
 }