Support hidden API processing for modules that use platform APIs
Previously, hidden API processing could only be done by those
bootclasspath_fragment modules that either did not depend on any other
fragments (e.g. art-bootclasspath-fragment) or only depended on APIs
provided by other fragments (e.g. i18n-bootclasspath-fragment). That
meant that modules like com.android.os.statsd-bootclasspath-fragment
that depended on APIs provided by parts of the platform which are not
yet part of another bootclasspath_fragment could not perform hidden
API processing.
This change adds support for a bootclasspath_fragment to specify the
additional stubs needed to perform hidden API processing. It adds a new
additional_stubs property that can be used to specify the additional
stub libraries.
Most bootclasspath_fragments that need to use the property will need
access to the APIs provided by the android-non-updatable.* libraries.
Rather than have each fragment explicitly specify the correct module
for each scope it treats "android-non-updatable" as if it was a
java_sdk_library that can provide different jars for each scope.
Soong will handle mapping that to the correct android-non-updatable.*
module.
Bug: 179354495
Test: m out/soong/hiddenapi/hiddenapi-flags.csv \
out/soong/hiddenapi/hiddenapi-index.csv \
out/soong/hiddenapi/hiddenapi-stub-flags.txt \
out/soong/hiddenapi/hiddenapi-unsupported.csv
- make sure that this change does not change the contents.
m TARGET_BUILD_APPS=Calendar nothing
Change-Id: Ia8b79830ed0e6d42100de03d76b0c51b7f6c8ade
diff --git a/java/bootclasspath_fragment.go b/java/bootclasspath_fragment.go
index 23e4e8d..8ea9f82 100644
--- a/java/bootclasspath_fragment.go
+++ b/java/bootclasspath_fragment.go
@@ -124,6 +124,15 @@
// Hidden API related properties.
Hidden_api HiddenAPIFlagFileProperties
+ // The list of additional stub libraries which this fragment's contents use but which are not
+ // provided by another bootclasspath_fragment.
+ //
+ // Note, "android-non-updatable" is treated specially. While no such module exists it is treated
+ // as if it was a java_sdk_library. So, when public API stubs are needed then it will be replaced
+ // with "android-non-updatable.stubs", with "androidn-non-updatable.system.stubs" when the system
+ // stubs are needed and so on.
+ Additional_stubs []string
+
// Properties that allow a fragment to depend on other fragments. This is needed for hidden API
// processing as it needs access to all the classes used by a fragment including those provided
// by other fragments.
@@ -381,6 +390,15 @@
// bootclasspath fragment.
hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs())
+ for _, additionalStubModule := range b.properties.Additional_stubs {
+ for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
+ // Add a dependency onto a possibly scope specific stub library.
+ scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule)
+ tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true}
+ ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency)
+ }
+ }
+
if SkipDexpreoptBootJars(ctx) {
return
}
@@ -640,8 +658,8 @@
// Populate with flag file paths from the properties.
input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api)
- // Store the stub dex jars from this module's fragment dependencies.
- input.DependencyStubDexJarsByScope = dependencyHiddenApiInfo.TransitiveStubDexJarsByScope
+ // Add the stub dex jars from this module's fragment dependencies.
+ input.DependencyStubDexJarsByScope.append(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope)
return input
}
diff --git a/java/hiddenapi_modular.go b/java/hiddenapi_modular.go
index 96534ad..b322c6f 100644
--- a/java/hiddenapi_modular.go
+++ b/java/hiddenapi_modular.go
@@ -37,13 +37,65 @@
// The option needed to passed to "hiddenapi list".
hiddenAPIListOption string
+
+ // The name sof the source stub library modules that contain the API provided by the platform,
+ // i.e. by modules that are not in an APEX.
+ nonUpdatableSourceModule string
+
+ // The names of the prebuilt stub library modules that contain the API provided by the platform,
+ // i.e. by modules that are not in an APEX.
+ nonUpdatablePrebuiltModule string
}
// initHiddenAPIScope initializes the scope.
func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
+ sdkKind := apiScope.sdkKind
+ // The platform does not provide a core platform API.
+ if sdkKind != android.SdkCorePlatform {
+ kindAsString := sdkKind.String()
+ var insert string
+ if sdkKind == android.SdkPublic {
+ insert = ""
+ } else {
+ insert = "." + strings.ReplaceAll(kindAsString, "-", "_")
+ }
+
+ nonUpdatableModule := "android-non-updatable"
+
+ // Construct the name of the android-non-updatable source module for this scope.
+ apiScope.nonUpdatableSourceModule = fmt.Sprintf("%s.stubs%s", nonUpdatableModule, insert)
+
+ prebuiltModuleName := func(name string, kind string) string {
+ return fmt.Sprintf("sdk_%s_current_%s", kind, name)
+ }
+
+ // Construct the name of the android-non-updatable prebuilt module for this scope.
+ apiScope.nonUpdatablePrebuiltModule = prebuiltModuleName(nonUpdatableModule, kindAsString)
+ }
+
return apiScope
}
+// android-non-updatable takes the name of a module and returns a possibly scope specific name of
+// the module.
+func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext, name string) string {
+ // The android-non-updatable is not a java_sdk_library but there are separate stub libraries for
+ // each scope.
+ // TODO(b/192067200): Remove special handling of android-non-updatable.
+ if name == "android-non-updatable" {
+ if ctx.Config().AlwaysUsePrebuiltSdks() {
+ return l.nonUpdatablePrebuiltModule
+ } else {
+ return l.nonUpdatableSourceModule
+ }
+ } else {
+ // Assume that the module is either a java_sdk_library (or equivalent) and so will provide
+ // separate stub jars for each scope or is a java_library (or equivalent) in which case it will
+ // have the same stub jar for each scope.
+ return name
+ }
+}
+
func (l *HiddenAPIScope) String() string {
return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
}
@@ -122,6 +174,11 @@
// The api scope for which this dependency was added.
apiScope *HiddenAPIScope
+
+ // Indicates that the dependency is not for an API provided by the current bootclasspath fragment
+ // but is an additional API provided by a module that is not part of the current bootclasspath
+ // fragment.
+ fromAdditionalDependency bool
}
func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
@@ -132,6 +189,11 @@
}
func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
+ // Do not add additional dependencies to the sdk.
+ if b.fromAdditionalDependency {
+ return nil
+ }
+
// If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
// property, otherwise treat if it was specified in the java_header_libs property.
if javaSdkLibrarySdkMemberType.IsInstance(child) {
@@ -243,15 +305,10 @@
tempPath := tempPathForRestat(ctx, outputPath)
// Find the widest API stubs provided by the fragments on which this depends, if any.
- var dependencyStubDexJars android.Paths
- for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
- apiScope := hiddenAPIScopes[i]
- stubsForAPIScope := input.DependencyStubDexJarsByScope[apiScope]
- if len(stubsForAPIScope) != 0 {
- dependencyStubDexJars = stubsForAPIScope
- break
- }
- }
+ dependencyStubDexJars := input.DependencyStubDexJarsByScope.stubDexJarsForWidestAPIScope()
+
+ // Add widest API stubs from the additional dependencies of this, if any.
+ dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.stubDexJarsForWidestAPIScope()...)
command := rule.Command().
Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
@@ -266,6 +323,7 @@
// other fragment's APIs.
var paths android.Paths
paths = append(paths, input.DependencyStubDexJarsByScope[apiScope]...)
+ paths = append(paths, input.AdditionalStubDexJarsByScope[apiScope]...)
paths = append(paths, input.StubDexJarsByScope[apiScope]...)
if len(paths) > 0 {
option := apiScope.hiddenAPIListOption
@@ -501,6 +559,20 @@
}
}
+// stubDexJarsForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
+// map. The relative width of APIs is determined by their order in hiddenAPIScopes.
+func (s StubDexJarsByScope) stubDexJarsForWidestAPIScope() android.Paths {
+ for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
+ apiScope := hiddenAPIScopes[i]
+ stubsForAPIScope := s[apiScope]
+ if len(stubsForAPIScope) != 0 {
+ return stubsForAPIScope
+ }
+ }
+
+ return nil
+}
+
// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
// needed for hidden API flag generation.
type HiddenAPIFlagInput struct {
@@ -517,6 +589,13 @@
// fragment on which this depends.
DependencyStubDexJarsByScope StubDexJarsByScope
+ // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to
+ // the ones that are obtained from fragments on which this depends.
+ //
+ // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope
+ // as there are not propagated transitively to other fragments that depend on this.
+ AdditionalStubDexJarsByScope StubDexJarsByScope
+
// RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
// specified in the bootclasspath_fragment's stub_libs and contents properties.
RemovedTxtFiles android.Paths
@@ -528,6 +607,7 @@
FlagFilesByCategory: FlagFilesByCategory{},
StubDexJarsByScope: StubDexJarsByScope{},
DependencyStubDexJarsByScope: StubDexJarsByScope{},
+ AdditionalStubDexJarsByScope: StubDexJarsByScope{},
}
return input
@@ -601,7 +681,14 @@
tag := ctx.OtherModuleDependencyTag(module)
if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
apiScope := hiddenAPIStubsTag.apiScope
- addFromModule(ctx, module, apiScope)
+ if hiddenAPIStubsTag.fromAdditionalDependency {
+ dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind)
+ if dexJar != nil {
+ i.AdditionalStubDexJarsByScope[apiScope] = append(i.AdditionalStubDexJarsByScope[apiScope], dexJar)
+ }
+ } else {
+ addFromModule(ctx, module, apiScope)
+ }
}
})