Add support for specifying api provided by bootclasspath_fragment
The hidden API processing needs access to dex stub jars for the API
scopes provided by the bootclasspath_fragment so that it can mark the
corresponding dex members as being part of that API. This change adds
the ability to specify the modules that provide those jars, resolve the
modules to dex jar stubs and make them available for other modules and
tests to use.
While the stubs are only needed for hidden API at the moment these were
not added to the hidden_api properties section as there are other parts
of the build that may need to access the stubs in future, e.g. api
fingerprint and aidl generation.
The stubs properties can be affected by coverage as when coverage is
enabled the jacoco-stubs needs adding to the list, just like how
jacocoagent is added to the contents.
Bug: 177892522
Test: m nothing
Change-Id: I31097d1ca45c84adeba4cbb38f693698cb289e99
diff --git a/java/bootclasspath.go b/java/bootclasspath.go
index c16193d..f03a673 100644
--- a/java/bootclasspath.go
+++ b/java/bootclasspath.go
@@ -161,3 +161,59 @@
// The tag used for dependencies onto bootclasspath_fragments.
var bootclasspathFragmentDepTag = bootclasspathDependencyTag{name: "fragment"}
+
+// BootclasspathNestedAPIProperties defines properties related to the API provided by parts of the
+// bootclasspath that are nested within the main BootclasspathAPIProperties.
+type BootclasspathNestedAPIProperties struct {
+ // java_library or preferably, java_sdk_library modules providing stub classes that define the
+ // APIs provided by this bootclasspath_fragment.
+ Stub_libs []string
+}
+
+// BootclasspathAPIProperties defines properties for defining the API provided by parts of the
+// bootclasspath.
+type BootclasspathAPIProperties struct {
+ // Api properties provide information about the APIs provided by the bootclasspath_fragment.
+ // Properties in this section apply to public, system and test api scopes. They DO NOT apply to
+ // core_platform as that is a special, ART specific scope, that does not follow the pattern and so
+ // has its own section. It is in the process of being deprecated and replaced by the system scope
+ // but this will remain for the foreseeable future to maintain backwards compatibility.
+ //
+ // Every bootclasspath_fragment must specify at least one stubs_lib in this section and must
+ // specify stubs for all the APIs provided by its contents. Failure to do so will lead to those
+ // methods being inaccessible to other parts of Android, including but not limited to
+ // applications.
+ Api BootclasspathNestedAPIProperties
+
+ // Properties related to the core platform API surface.
+ //
+ // This must only be used by the following modules:
+ // * ART
+ // * Conscrypt
+ // * I18N
+ //
+ // The bootclasspath_fragments for each of the above modules must specify at least one stubs_lib
+ // and must specify stubs for all the APIs provided by its contents. Failure to do so will lead to
+ // those methods being inaccessible to the other modules in the list.
+ Core_platform_api BootclasspathNestedAPIProperties
+}
+
+// sdkKindToStubLibs calculates the stub library modules for each relevant android.SdkKind from the
+// Stub_libs properties.
+func (p BootclasspathAPIProperties) sdkKindToStubLibs() map[android.SdkKind][]string {
+ m := map[android.SdkKind][]string{}
+ for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
+ m[kind] = p.Api.Stub_libs
+ }
+ m[android.SdkCorePlatform] = p.Core_platform_api.Stub_libs
+ return m
+}
+
+// bootclasspathApiInfo contains paths resolved from BootclasspathAPIProperties
+type bootclasspathApiInfo struct {
+ // stubJarsByKind maps from the android.SdkKind to the paths containing dex stub jars for each
+ // kind.
+ stubJarsByKind map[android.SdkKind]android.Paths
+}
+
+var bootclasspathApiInfoProvider = blueprint.NewProvider(bootclasspathApiInfo{})
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 5c1c5f0..6ea3819 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -88,6 +88,9 @@
//
// The order of this list matters as it is the order that is used in the bootclasspath.
Contents []string
+
+ // The properties for specifying the API stubs provided by this fragment.
+ BootclasspathAPIProperties
}
type bootclasspathFragmentProperties struct {
@@ -316,6 +319,9 @@
}
func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) {
+ // Add dependencies onto all the modules that provide the API stubs for classes on this
+ // bootclasspath fragment.
+ hiddenAPIAddStubLibDependencies(ctx, b.properties.sdkKindToStubLibs())
if SkipDexpreoptBootJars(ctx) {
return
@@ -384,6 +390,13 @@
// Store the information for use by platform_bootclasspath.
ctx.SetProvider(hiddenAPIFlagFileInfoProvider, flagFileInfo)
+
+ // Convert the kind specific lists of modules into kind specific lists of jars.
+ stubJarsByKind := hiddenAPIGatherStubLibDexJarPaths(ctx)
+
+ // Store the information for use by other modules.
+ bootclasspathApiInfo := bootclasspathApiInfo{stubJarsByKind: stubJarsByKind}
+ ctx.SetProvider(bootclasspathApiInfoProvider, bootclasspathApiInfo)
}
type bootclasspathFragmentMemberType struct {
diff --git a/java/bootclasspath_fragment_test.go b/java/bootclasspath_fragment_test.go
index 0419a46..dbdf6c4 100644
--- a/java/bootclasspath_fragment_test.go
+++ b/java/bootclasspath_fragment_test.go
@@ -171,3 +171,68 @@
checkContents(t, result, "mybootlib", "coveragelib")
})
}
+
+func TestBootclasspathFragment_StubLibs(t *testing.T) {
+ result := android.GroupFixturePreparers(
+ prepareForTestWithBootclasspathFragment,
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("mysdklibrary", "mycoreplatform"),
+ ).RunTestWithBp(t, `
+ bootclasspath_fragment {
+ name: "myfragment",
+ contents: ["mysdklibrary"],
+ api: {
+ stub_libs: [
+ "mystublib",
+ "mysdklibrary",
+ ],
+ },
+ core_platform_api: {
+ stub_libs: ["mycoreplatform"],
+ },
+ }
+
+ java_library {
+ name: "mystublib",
+ srcs: ["Test.java"],
+ system_modules: "none",
+ sdk_version: "none",
+ compile_dex: true,
+ }
+
+ java_sdk_library {
+ name: "mysdklibrary",
+ srcs: ["a.java"],
+ compile_dex: true,
+ public: {enabled: true},
+ system: {enabled: true},
+ }
+
+ java_sdk_library {
+ name: "mycoreplatform",
+ srcs: ["a.java"],
+ compile_dex: true,
+ public: {enabled: true},
+ }
+ `)
+
+ fragment := result.Module("myfragment", "android_common")
+ info := result.ModuleProvider(fragment, bootclasspathApiInfoProvider).(bootclasspathApiInfo)
+
+ stubsJar := "out/soong/.intermediates/mystublib/android_common/dex/mystublib.jar"
+
+ // Check that SdkPublic uses public stubs.
+ publicStubsJar := "out/soong/.intermediates/mysdklibrary.stubs/android_common/dex/mysdklibrary.stubs.jar"
+ android.AssertPathsRelativeToTopEquals(t, "public dex stubs jar", []string{stubsJar, publicStubsJar}, info.stubJarsByKind[android.SdkPublic])
+
+ // Check that SdkSystem uses system stubs.
+ systemStubsJar := "out/soong/.intermediates/mysdklibrary.stubs.system/android_common/dex/mysdklibrary.stubs.system.jar"
+ android.AssertPathsRelativeToTopEquals(t, "system dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkSystem])
+
+ // Check that SdkTest also uses system stubs as the mysdklibrary does not provide test stubs.
+ android.AssertPathsRelativeToTopEquals(t, "test dex stubs jar", []string{stubsJar, systemStubsJar}, info.stubJarsByKind[android.SdkTest])
+
+ // Check that SdkCorePlatform uses public stubs from the mycoreplatform library.
+ corePlatformStubsJar := "out/soong/.intermediates/mycoreplatform.stubs/android_common/dex/mycoreplatform.stubs.jar"
+ android.AssertPathsRelativeToTopEquals(t, "core platform dex stubs jar", []string{corePlatformStubsJar}, info.stubJarsByKind[android.SdkCorePlatform])
+}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 793d63a..335f5b8 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -127,7 +127,7 @@
tag := ctx.OtherModuleDependencyTag(module)
if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
kind := hiddenAPIStubsTag.sdkKind
- dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module)
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
if dexJar != nil {
m[kind] = append(m[kind], dexJar)
}
@@ -138,17 +138,21 @@
// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
// available, or reports an error.
-func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module) android.Path {
- if j, ok := module.(UsesLibraryDependency); ok {
- dexJar := j.DexJarBuildPath()
- if dexJar != nil {
- return dexJar
- }
- ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
+func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
+ var dexJar android.Path
+ if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
+ dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
+ } else if j, ok := module.(UsesLibraryDependency); ok {
+ dexJar = j.DexJarBuildPath()
} else {
ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module))
+ return nil
}
- return nil
+
+ if dexJar == nil {
+ ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
+ }
+ return dexJar
}
var sdkKindToHiddenapiListOption = map[android.SdkKind]string{