diff --git a/java/bootclasspath.go b/java/bootclasspath.go index c16193d73..f03a67302 100644 --- a/java/bootclasspath.go +++ b/java/bootclasspath.go @@ -161,3 +161,59 @@ var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathDependencyTag{} // 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 5c1c5f0c9..6ea3819d5 100644 --- a/java/bootclasspath_fragment.go +++ b/java/bootclasspath_fragment.go @@ -88,6 +88,9 @@ type BootclasspathFragmentCoverageAffectedProperties struct { // // 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) ComponentDepsMutator(ctx android.BottomUpM } 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 @@ func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android. // 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 0419a469b..dbdf6c413 100644 --- a/java/bootclasspath_fragment_test.go +++ b/java/bootclasspath_fragment_test.go @@ -171,3 +171,68 @@ func TestBootclasspathFragment_Coverage(t *testing.T) { 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 793d63ae7..335f5b861 100644 --- a/java/hiddenapi_modular.go +++ b/java/hiddenapi_modular.go @@ -127,7 +127,7 @@ func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext) map[android.Sd 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 @@ func hiddenAPIGatherStubLibDexJarPaths(ctx android.ModuleContext) map[android.Sd // 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{