Create (API) bp2build converters for droidstubs
- The converter runs for api_bp2build, not bp2build workspace
- Since droidstubs is an internal module created by java_sdk_library,
the conversion encompasses the latter as well
- Since droidstubs do not have an api_surface attribute, this conversion
uses naming convention to infer the api_surface represented by the api
file e.g. *stubs.source -> publicapi, *stubs.source.system -> systemapi)
- Also adds an SdkIntraCore enum to represent the API surface provided
by one core module to another
There is also ongoing work to check in java_api_contribution modules in
Soong. Once we have that, we can update this converter to operate on
that module type instead
Test: go test ./bp2build
Change-Id: Ia85828e04c738d9ffcc524856d7c3034ee29bbf9
diff --git a/android/api_domain.go b/android/api_domain.go
index 3265148..bdd4e6f 100644
--- a/android/api_domain.go
+++ b/android/api_domain.go
@@ -59,8 +59,14 @@
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
+ // This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
+ // will provide a `CcApiContributionInfo` provider
Cc_api_contributions []string
+
+ // java library contributions (as .txt) of this API domain
+ // This dependency is a no-op in Soong, but the corresponding Bazel target in the api_bp2build workspace
+ // will provide a `JavaApiContributionInfo` provider
+ Java_api_contributions []string
}
func ApiDomainFactory() Module {
@@ -102,7 +108,8 @@
}
type bazelApiDomainAttributes struct {
- Cc_api_contributions bazel.LabelListAttribute
+ Cc_api_contributions bazel.LabelListAttribute
+ Java_api_contributions bazel.LabelListAttribute
}
var _ ApiProvider = (*apiDomain)(nil)
@@ -113,7 +120,8 @@
Bzl_load_location: "//build/bazel/rules/apis:api_domain.bzl",
}
attrs := &bazelApiDomainAttributes{
- Cc_api_contributions: contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
+ Cc_api_contributions: contributionBazelAttributes(ctx, a.properties.Cc_api_contributions),
+ Java_api_contributions: contributionBazelAttributes(ctx, a.properties.Java_api_contributions),
}
ctx.CreateBazelTargetModule(props, CommonAttributes{
Name: ctx.ModuleName(),
diff --git a/android/sdk_version.go b/android/sdk_version.go
index c188c48..d73c912 100644
--- a/android/sdk_version.go
+++ b/android/sdk_version.go
@@ -44,6 +44,7 @@
SdkNone
SdkCore
SdkCorePlatform
+ SdkIntraCore // API surface provided by one core module to another
SdkPublic
SdkSystem
SdkTest
@@ -69,6 +70,8 @@
return "core"
case SdkCorePlatform:
return "core_platform"
+ case SdkIntraCore:
+ return "intracore"
case SdkModule:
return "module-lib"
case SdkSystemServer:
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 7c9af1a..5547c94 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -54,6 +54,7 @@
"cc_test_conversion_test.go",
"cc_yasm_conversion_test.go",
"conversion_test.go",
+ "droidstubs_conversion_test.go",
"filegroup_conversion_test.go",
"genrule_conversion_test.go",
"gensrcs_conversion_test.go",
diff --git a/bp2build/droidstubs_conversion_test.go b/bp2build/droidstubs_conversion_test.go
new file mode 100644
index 0000000..12c1cfe
--- /dev/null
+++ b/bp2build/droidstubs_conversion_test.go
@@ -0,0 +1,104 @@
+// 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/java"
+)
+
+func registerJavaApiModules(ctx android.RegistrationContext) {
+ java.RegisterSdkLibraryBuildComponents(ctx)
+ java.RegisterStubsBuildComponents(ctx)
+}
+
+func TestDroidstubsApiContributions(t *testing.T) {
+ bp := `
+ droidstubs {
+ name: "framework-stubs",
+ check_api: {
+ current: {
+ api_file: "framework.current.txt",
+ },
+ },
+ }
+
+ // Modules without check_api should not generate a Bazel API target
+ droidstubs {
+ name: "framework-docs",
+ }
+
+ // java_sdk_library is a macro that creates droidstubs
+ java_sdk_library {
+ name: "module-stubs",
+ srcs: ["A.java"],
+
+ // These api surfaces are added by default, but add them explicitly to make
+ // this test hermetic
+ public: {
+ enabled: true,
+ },
+ system: {
+ enabled: true,
+ },
+
+ // Disable other api surfaces to keep unit test scope limited
+ module_lib: {
+ enabled: false,
+ },
+ test: {
+ enabled: false,
+ },
+ }
+ `
+ expectedBazelTargets := []string{
+ MakeBazelTargetNoRestrictions(
+ "java_api_contribution",
+ "framework-stubs.contribution",
+ AttrNameToString{
+ "api": `"framework.current.txt"`,
+ "api_surface": `"publicapi"`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ }),
+ MakeBazelTargetNoRestrictions(
+ "java_api_contribution",
+ "module-stubs.stubs.source.contribution",
+ AttrNameToString{
+ "api": `"api/current.txt"`,
+ "api_surface": `"publicapi"`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ }),
+ MakeBazelTargetNoRestrictions(
+ "java_api_contribution",
+ "module-stubs.stubs.source.system.contribution",
+ AttrNameToString{
+ "api": `"api/system-current.txt"`,
+ "api_surface": `"systemapi"`,
+ "target_compatible_with": `["//build/bazel/platforms/os:android"]`,
+ }),
+ }
+ RunApiBp2BuildTestCase(t, registerJavaApiModules, Bp2buildTestCase{
+ Blueprint: bp,
+ ExpectedBazelTargets: expectedBazelTargets,
+ Filesystem: map[string]string{
+ "api/current.txt": "",
+ "api/removed.txt": "",
+ "api/system-current.txt": "",
+ "api/system-removed.txt": "",
+ },
+ })
+}
diff --git a/java/droidstubs.go b/java/droidstubs.go
index 5777b18..2ad2969 100644
--- a/java/droidstubs.go
+++ b/java/droidstubs.go
@@ -18,11 +18,13 @@
"fmt"
"path/filepath"
"regexp"
+ "sort"
"strings"
"github.com/google/blueprint/proptools"
"android/soong/android"
+ "android/soong/bazel"
"android/soong/java/config"
"android/soong/remoteexec"
)
@@ -834,6 +836,74 @@
}
}
+var _ android.ApiProvider = (*Droidstubs)(nil)
+
+type bazelJavaApiContributionAttributes struct {
+ Api bazel.LabelAttribute
+ Api_surface *string
+}
+
+func (d *Droidstubs) ConvertWithApiBp2build(ctx android.TopDownMutatorContext) {
+ props := bazel.BazelTargetModuleProperties{
+ Rule_class: "java_api_contribution",
+ Bzl_load_location: "//build/bazel/rules/apis:java_api_contribution.bzl",
+ }
+ apiFile := d.properties.Check_api.Current.Api_file
+ // Do not generate a target if check_api is not set
+ if apiFile == nil {
+ return
+ }
+ attrs := &bazelJavaApiContributionAttributes{
+ Api: *bazel.MakeLabelAttribute(
+ android.BazelLabelForModuleSrcSingle(ctx, proptools.String(apiFile)).Label,
+ ),
+ Api_surface: proptools.StringPtr(bazelApiSurfaceName(d.Name())),
+ }
+ ctx.CreateBazelTargetModule(props, android.CommonAttributes{
+ Name: android.ApiContributionTargetName(ctx.ModuleName()),
+ }, attrs)
+}
+
+// TODO (b/262014796): Export the API contributions of CorePlatformApi
+// A map to populate the api surface of a droidstub from a substring appearing in its name
+// This map assumes that droidstubs (either checked-in or created by java_sdk_library)
+// use a strict naming convention
+var (
+ droidstubsModuleNamingToSdkKind = map[string]android.SdkKind{
+ //public is commented out since the core libraries use public in their java_sdk_library names
+ "intracore": android.SdkIntraCore,
+ "intra.core": android.SdkIntraCore,
+ "system_server": android.SdkSystemServer,
+ "system-server": android.SdkSystemServer,
+ "system": android.SdkSystem,
+ "module_lib": android.SdkModule,
+ "module-lib": android.SdkModule,
+ "test": android.SdkTest,
+ }
+)
+
+// A helper function that returns the api surface of the corresponding java_api_contribution Bazel target
+// The api_surface is populated using the naming convention of the droidstubs module.
+func bazelApiSurfaceName(name string) string {
+ // Sort the keys so that longer strings appear first
+ // Otherwise substrings like system will match both system and system_server
+ sortedKeys := make([]string, 0)
+ for key := range droidstubsModuleNamingToSdkKind {
+ sortedKeys = append(sortedKeys, key)
+ }
+ sort.Slice(sortedKeys, func(i, j int) bool {
+ return len(sortedKeys[i]) > len(sortedKeys[j])
+ })
+ for _, sortedKey := range sortedKeys {
+ if strings.Contains(name, sortedKey) {
+ sdkKind := droidstubsModuleNamingToSdkKind[sortedKey]
+ return sdkKind.String() + "api"
+ }
+ }
+ // Default is publicapi
+ return android.SdkPublic.String() + "api"
+}
+
func StubsDefaultsFactory() android.Module {
module := &DocDefaults{}
diff --git a/java/droidstubs_test.go b/java/droidstubs_test.go
index 25f8c86..ef2e6dc 100644
--- a/java/droidstubs_test.go
+++ b/java/droidstubs_test.go
@@ -304,3 +304,45 @@
android.AssertStringDoesContain(t, "sdk-extensions-root present", cmdline, "--sdk-extensions-root sdk/extensions")
android.AssertStringDoesContain(t, "sdk-extensions-info present", cmdline, "--sdk-extensions-info sdk/extensions/info.txt")
}
+
+func TestApiSurfaceFromDroidStubsName(t *testing.T) {
+ testCases := []struct {
+ desc string
+ name string
+ expectedApiSurface string
+ }{
+ {
+ desc: "Default is publicapi",
+ name: "mydroidstubs",
+ expectedApiSurface: "publicapi",
+ },
+ {
+ desc: "name contains system substring",
+ name: "mydroidstubs.system.suffix",
+ expectedApiSurface: "systemapi",
+ },
+ {
+ desc: "name contains system_server substring",
+ name: "mydroidstubs.system_server.suffix",
+ expectedApiSurface: "system-serverapi",
+ },
+ {
+ desc: "name contains module_lib substring",
+ name: "mydroidstubs.module_lib.suffix",
+ expectedApiSurface: "module-libapi",
+ },
+ {
+ desc: "name contains test substring",
+ name: "mydroidstubs.test.suffix",
+ expectedApiSurface: "testapi",
+ },
+ {
+ desc: "name contains intra.core substring",
+ name: "mydroidstubs.intra.core.suffix",
+ expectedApiSurface: "intracoreapi",
+ },
+ }
+ for _, tc := range testCases {
+ android.AssertStringEquals(t, tc.desc, tc.expectedApiSurface, bazelApiSurfaceName(tc.name))
+ }
+}