2021-04-08 18:49:27 +02:00
// Copyright (C) 2021 The Android Open Source Project
//
// 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 java
import (
2021-05-19 10:36:09 +02:00
"fmt"
2021-05-13 18:31:51 +02:00
"strings"
2021-04-08 18:49:27 +02:00
"android/soong/android"
2021-09-15 04:34:04 +02:00
2021-04-09 00:01:37 +02:00
"github.com/google/blueprint"
2021-04-08 18:49:27 +02:00
)
// Contains support for processing hiddenAPI in a modular fashion.
2021-06-18 19:14:25 +02:00
// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API
// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do
// not provide the information needed by hidden API processing.
type HiddenAPIScope struct {
// The name of the scope, used for debug purposes.
name string
// The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules.
sdkKind android . SdkKind
// The option needed to passed to "hiddenapi list".
hiddenAPIListOption string
2021-05-26 11:16:01 +02:00
2023-10-06 18:54:58 +02:00
// The names of the source stub library modules that contain the API provided by the platform,
2021-05-26 11:16:01 +02:00
// i.e. by modules that are not in an APEX.
nonUpdatableSourceModule string
2023-10-06 18:54:58 +02:00
// The names of from-text stub library modules that contain the API provided by the platform,
// i.e. by modules that are not in an APEX.
nonUpdatableFromTextModule string
2021-05-26 11:16:01 +02:00
// 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
2021-06-18 19:14:25 +02:00
}
// initHiddenAPIScope initializes the scope.
func initHiddenAPIScope ( apiScope * HiddenAPIScope ) * HiddenAPIScope {
2021-05-26 11:16:01 +02:00
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 )
}
2021-06-18 19:14:25 +02:00
return apiScope
}
2021-05-26 11:16:01 +02:00
// 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 {
2023-10-06 18:54:58 +02:00
if l . nonUpdatableFromTextModule != "" && ctx . Config ( ) . BuildFromTextStub ( ) {
return l . nonUpdatableFromTextModule
}
2021-05-26 11:16:01 +02:00
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
}
}
2021-06-18 19:14:25 +02:00
func ( l * HiddenAPIScope ) String ( ) string {
return fmt . Sprintf ( "HiddenAPIScope{%s}" , l . name )
}
var (
PublicHiddenAPIScope = initHiddenAPIScope ( & HiddenAPIScope {
name : "public" ,
sdkKind : android . SdkPublic ,
hiddenAPIListOption : "--public-stub-classpath" ,
} )
SystemHiddenAPIScope = initHiddenAPIScope ( & HiddenAPIScope {
name : "system" ,
sdkKind : android . SdkSystem ,
hiddenAPIListOption : "--system-stub-classpath" ,
} )
TestHiddenAPIScope = initHiddenAPIScope ( & HiddenAPIScope {
name : "test" ,
sdkKind : android . SdkTest ,
hiddenAPIListOption : "--test-stub-classpath" ,
} )
2021-06-21 15:08:08 +02:00
ModuleLibHiddenAPIScope = initHiddenAPIScope ( & HiddenAPIScope {
2023-10-06 18:54:58 +02:00
name : "module-lib" ,
sdkKind : android . SdkModule ,
nonUpdatableFromTextModule : "android-non-updatable.stubs.test_module_lib" ,
2021-06-21 15:08:08 +02:00
} )
2021-06-18 19:14:25 +02:00
CorePlatformHiddenAPIScope = initHiddenAPIScope ( & HiddenAPIScope {
name : "core-platform" ,
sdkKind : android . SdkCorePlatform ,
hiddenAPIListOption : "--core-platform-stub-classpath" ,
} )
// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
// API processing.
//
// These are roughly in order from narrowest API surface to widest. Widest means the API stubs
// with the biggest API surface, e.g. test is wider than system is wider than public.
//
2021-06-21 15:08:08 +02:00
// Core platform is considered wider than system/module-lib because those modules that provide
// core platform APIs either do not have any system/module-lib APIs at all, or if they do it is
// because the core platform API is being converted to system/module-lib APIs. In either case the
// system/module-lib APIs are subsets of the core platform API.
2021-06-18 19:14:25 +02:00
//
// This is not strictly in order from narrowest to widest as the Test API is wider than system but
2021-06-21 15:08:08 +02:00
// is neither wider or narrower than the module-lib or core platform APIs. However, this works
// well enough at the moment.
2021-06-18 19:14:25 +02:00
// TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
hiddenAPIScopes = [ ] * HiddenAPIScope {
PublicHiddenAPIScope ,
SystemHiddenAPIScope ,
TestHiddenAPIScope ,
2021-06-21 15:08:08 +02:00
ModuleLibHiddenAPIScope ,
2021-06-18 19:14:25 +02:00
CorePlatformHiddenAPIScope ,
}
// The HiddenAPIScope instances that are supported by a java_sdk_library.
//
// CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
// for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
hiddenAPISdkLibrarySupportedScopes = [ ] * HiddenAPIScope {
PublicHiddenAPIScope ,
SystemHiddenAPIScope ,
TestHiddenAPIScope ,
2021-06-21 15:08:08 +02:00
ModuleLibHiddenAPIScope ,
2021-06-18 19:14:25 +02:00
}
// The HiddenAPIScope instances that are supported by the `hiddenapi list`.
hiddenAPIFlagScopes = [ ] * HiddenAPIScope {
PublicHiddenAPIScope ,
SystemHiddenAPIScope ,
TestHiddenAPIScope ,
CorePlatformHiddenAPIScope ,
}
)
2021-04-21 15:10:42 +02:00
type hiddenAPIStubsDependencyTag struct {
blueprint . BaseDependencyTag
2021-06-18 19:14:25 +02:00
// The api scope for which this dependency was added.
apiScope * HiddenAPIScope
2021-05-26 11:16:01 +02:00
// 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
2021-04-21 15:10:42 +02:00
}
func ( b hiddenAPIStubsDependencyTag ) ExcludeFromApexContents ( ) {
}
func ( b hiddenAPIStubsDependencyTag ) ReplaceSourceWithPrebuilt ( ) bool {
return false
}
2021-04-28 00:20:26 +02:00
func ( b hiddenAPIStubsDependencyTag ) SdkMemberType ( child android . Module ) android . SdkMemberType {
2021-05-26 11:16:01 +02:00
// Do not add additional dependencies to the sdk.
if b . fromAdditionalDependency {
return nil
}
2021-04-28 00:20:26 +02:00
// 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 ) {
return javaSdkLibrarySdkMemberType
}
return javaHeaderLibsSdkMemberType
}
func ( b hiddenAPIStubsDependencyTag ) ExportMember ( ) bool {
// Export the module added via this dependency tag from the sdk.
return true
}
2021-04-21 15:10:42 +02:00
// Avoid having to make stubs content explicitly visible to dependent modules.
//
// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
// with proper dependencies.
// TODO(b/177892522): Remove this and add needed visibility.
func ( b hiddenAPIStubsDependencyTag ) ExcludeFromVisibilityEnforcement ( ) {
}
var _ android . ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag { }
var _ android . ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag { }
var _ android . ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag { }
2021-09-02 15:29:21 +02:00
var _ android . SdkMemberDependencyTag = hiddenAPIStubsDependencyTag { }
2021-04-21 15:10:42 +02:00
// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
// needed to produce the hidden API monolithic stub flags file.
2021-06-18 19:14:25 +02:00
func hiddenAPIComputeMonolithicStubLibModules ( config android . Config ) map [ * HiddenAPIScope ] [ ] string {
2021-04-21 15:10:42 +02:00
var publicStubModules [ ] string
var systemStubModules [ ] string
var testStubModules [ ] string
var corePlatformStubModules [ ] string
if config . AlwaysUsePrebuiltSdks ( ) {
// Build configuration mandates using prebuilt stub modules
publicStubModules = append ( publicStubModules , "sdk_public_current_android" )
systemStubModules = append ( systemStubModules , "sdk_system_current_android" )
testStubModules = append ( testStubModules , "sdk_test_current_android" )
} else {
// Use stub modules built from source
2023-05-30 21:12:28 +02:00
publicStubModules = append ( publicStubModules , android . SdkPublic . DefaultJavaLibraryName ( ) )
systemStubModules = append ( systemStubModules , android . SdkSystem . DefaultJavaLibraryName ( ) )
testStubModules = append ( testStubModules , android . SdkTest . DefaultJavaLibraryName ( ) )
2021-04-21 15:10:42 +02:00
}
// We do not have prebuilts of the core platform api yet
2023-05-30 21:12:28 +02:00
corePlatformStubModules = append ( corePlatformStubModules , "legacy.core.platform.api.stubs" )
2021-04-21 15:10:42 +02:00
// Allow products to define their own stubs for custom product jars that apps can use.
publicStubModules = append ( publicStubModules , config . ProductHiddenAPIStubs ( ) ... )
systemStubModules = append ( systemStubModules , config . ProductHiddenAPIStubsSystem ( ) ... )
testStubModules = append ( testStubModules , config . ProductHiddenAPIStubsTest ( ) ... )
if config . IsEnvTrue ( "EMMA_INSTRUMENT" ) {
2021-05-14 11:45:25 +02:00
// Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
// allows everyone access but it is needed to ensure consistent flags between the
// bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
2021-04-21 15:10:42 +02:00
publicStubModules = append ( publicStubModules , "jacoco-stubs" )
2021-05-14 11:45:25 +02:00
systemStubModules = append ( systemStubModules , "jacoco-stubs" )
testStubModules = append ( testStubModules , "jacoco-stubs" )
2021-04-21 15:10:42 +02:00
}
2021-06-18 19:14:25 +02:00
m := map [ * HiddenAPIScope ] [ ] string { }
m [ PublicHiddenAPIScope ] = publicStubModules
m [ SystemHiddenAPIScope ] = systemStubModules
m [ TestHiddenAPIScope ] = testStubModules
m [ CorePlatformHiddenAPIScope ] = corePlatformStubModules
2021-04-21 15:10:42 +02:00
return m
}
// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
2021-06-18 19:14:25 +02:00
// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
// tag to identify the source of the dependency.
func hiddenAPIAddStubLibDependencies ( ctx android . BottomUpMutatorContext , apiScopeToStubLibModules map [ * HiddenAPIScope ] [ ] string ) {
2021-04-21 15:10:42 +02:00
module := ctx . Module ( )
2021-06-18 19:14:25 +02:00
for _ , apiScope := range hiddenAPIScopes {
modules := apiScopeToStubLibModules [ apiScope ]
ctx . AddDependency ( module , hiddenAPIStubsDependencyTag { apiScope : apiScope } , modules ... )
2021-04-21 15:10:42 +02:00
}
}
// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
// available, or reports an error.
2021-04-25 11:13:54 +02:00
func hiddenAPIRetrieveDexJarBuildPath ( ctx android . ModuleContext , module android . Module , kind android . SdkKind ) android . Path {
2021-09-15 04:34:04 +02:00
var dexJar OptionalDexJarPath
2021-04-25 11:13:54 +02:00
if sdkLibrary , ok := module . ( SdkLibraryDependency ) ; ok {
dexJar = sdkLibrary . SdkApiStubDexJar ( ctx , kind )
} else if j , ok := module . ( UsesLibraryDependency ) ; ok {
dexJar = j . DexJarBuildPath ( )
2021-04-21 15:10:42 +02:00
} else {
ctx . ModuleErrorf ( "dependency %s of module type %s does not support providing a dex jar" , module , ctx . OtherModuleType ( module ) )
2021-04-25 11:13:54 +02:00
return nil
}
2021-09-15 04:34:04 +02:00
if ! dexJar . Valid ( ) {
ctx . ModuleErrorf ( "dependency %s does not provide a dex jar: %s" , module , dexJar . InvalidReason ( ) )
return nil
2021-04-21 15:10:42 +02:00
}
2021-09-15 04:34:04 +02:00
return dexJar . Path ( )
2021-04-21 15:10:42 +02:00
}
2022-04-08 00:32:19 +02:00
// HIDDENAPI_STUB_FLAGS_IMPL_FLAGS is the set of flags that identify implementation only signatures,
// i.e. those signatures that are not part of any API (including the hidden API).
var HIDDENAPI_STUB_FLAGS_IMPL_FLAGS = [ ] string { }
var HIDDENAPI_FLAGS_CSV_IMPL_FLAGS = [ ] string { "blocked" }
2021-06-24 00:20:43 +02:00
// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
2021-04-21 15:10:42 +02:00
//
// The rule is initialized but not built so that the caller can modify it and select an appropriate
// name.
2021-07-21 18:38:47 +02:00
func buildRuleToGenerateHiddenAPIStubFlagsFile ( ctx android . BuilderContext , name , desc string , outputPath android . WritablePath , bootDexJars android . Paths , input HiddenAPIFlagInput , stubFlagSubsets SignatureCsvSubsets ) {
2021-04-21 15:10:42 +02:00
// Singleton rule which applies hiddenapi on all boot class path dex files.
rule := android . NewRuleBuilder ( pctx , ctx )
tempPath := tempPathForRestat ( ctx , outputPath )
2021-05-17 08:38:47 +02:00
// Find the widest API stubs provided by the fragments on which this depends, if any.
2021-06-27 21:53:39 +02:00
dependencyStubDexJars := input . DependencyStubDexJarsByScope . StubDexJarsForWidestAPIScope ( )
2021-05-26 11:16:01 +02:00
// Add widest API stubs from the additional dependencies of this, if any.
2021-06-27 21:53:39 +02:00
dependencyStubDexJars = append ( dependencyStubDexJars , input . AdditionalStubDexJarsByScope . StubDexJarsForWidestAPIScope ( ) ... )
2021-05-17 08:38:47 +02:00
2021-04-21 15:10:42 +02:00
command := rule . Command ( ) .
Tool ( ctx . Config ( ) . HostToolPath ( ctx , "hiddenapi" ) ) .
Text ( "list" ) .
2021-05-17 08:38:47 +02:00
FlagForEachInput ( "--dependency-stub-dex=" , dependencyStubDexJars ) .
2021-04-21 15:10:42 +02:00
FlagForEachInput ( "--boot-dex=" , bootDexJars )
2021-06-25 00:06:52 +02:00
// If no module stub flags paths are provided then this must be being called for a
// bootclasspath_fragment and not the whole platform_bootclasspath.
2021-07-21 18:38:47 +02:00
if stubFlagSubsets == nil {
2021-06-25 00:06:52 +02:00
// This is being run on a fragment of the bootclasspath.
command . Flag ( "--fragment" )
}
2021-06-18 19:14:25 +02:00
// Iterate over the api scopes in a fixed order.
for _ , apiScope := range hiddenAPIFlagScopes {
// Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
// They will be needed to resolve dependencies from this fragment's stubs to classes in the
// other fragment's APIs.
var paths android . Paths
2021-06-27 21:28:29 +02:00
paths = append ( paths , input . DependencyStubDexJarsByScope . StubDexJarsForScope ( apiScope ) ... )
paths = append ( paths , input . AdditionalStubDexJarsByScope . StubDexJarsForScope ( apiScope ) ... )
paths = append ( paths , input . StubDexJarsByScope . StubDexJarsForScope ( apiScope ) ... )
2021-04-21 15:10:42 +02:00
if len ( paths ) > 0 {
2021-06-18 19:14:25 +02:00
option := apiScope . hiddenAPIListOption
command . FlagWithInputList ( option + "=" , paths , ":" )
2021-04-21 15:10:42 +02:00
}
}
// Add the output path.
command . FlagWithOutput ( "--out-api-flags=" , tempPath )
2021-06-24 00:29:09 +02:00
// If there are stub flag files that have been generated by fragments on which this depends then
// use them to validate the stub flag file generated by the rules created by this method.
2023-11-01 14:58:39 +01:00
if ! ctx . Config ( ) . DisableVerifyOverlaps ( ) && len ( stubFlagSubsets ) > 0 {
2022-04-08 00:32:19 +02:00
validFile := buildRuleValidateOverlappingCsvFiles ( ctx , name , desc , outputPath , stubFlagSubsets ,
HIDDENAPI_STUB_FLAGS_IMPL_FLAGS )
2021-06-24 00:29:09 +02:00
// Add the file that indicates that the file generated by this is valid.
//
// This will cause the validation rule above to be run any time that the output of this rule
// changes but the validation will run in parallel with other rules that depend on this file.
command . Validation ( validFile )
}
2021-04-21 15:10:42 +02:00
commitChangeForRestat ( rule , tempPath , outputPath )
2021-06-24 00:20:43 +02:00
rule . Build ( name , desc )
2021-04-21 15:10:42 +02:00
}
2021-04-14 16:01:56 +02:00
// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
// information obtained from annotations within the source code in order to create the complete set
// of flags that should be applied to the dex implementation jars on the bootclasspath.
2021-04-08 18:49:27 +02:00
//
// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
// of each property reference a plain text file that contains a java signature per line. The flags
// for each of those signatures will be updated in a property specific way.
//
// The Unsupported_packages property contains a list of paths, each of which is a plain text file
// with one Java package per line. All members of all classes within that package (but not nested
// packages) will be updated in a property specific way.
2021-04-14 16:01:56 +02:00
type HiddenAPIFlagFileProperties struct {
2022-07-27 18:16:54 +02:00
Hidden_api struct {
// Marks each signature in the referenced files as being unsupported.
Unsupported [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being unsupported because it has been
// removed. Any conflicts with other flags are ignored.
Removed [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being supported only for
// targetSdkVersion <= R and low priority.
Max_target_r_low_priority [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being supported only for
// targetSdkVersion <= Q.
Max_target_q [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being supported only for
// targetSdkVersion <= P.
Max_target_p [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being supported only for
// targetSdkVersion <= O
// and low priority. Any conflicts with other flags are ignored.
Max_target_o_low_priority [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in the referenced files as being blocked.
Blocked [ ] string ` android:"path" `
2021-04-08 18:49:27 +02:00
2022-07-27 18:16:54 +02:00
// Marks each signature in every package in the referenced files as being unsupported.
Unsupported_packages [ ] string ` android:"path" `
}
2021-04-08 21:12:41 +02:00
}
2021-04-14 10:50:43 +02:00
type hiddenAPIFlagFileCategory struct {
2021-06-09 15:39:28 +02:00
// PropertyName is the name of the property for this category.
PropertyName string
2021-04-08 21:12:41 +02:00
2021-04-19 14:21:20 +02:00
// propertyValueReader retrieves the value of the property for this category from the set of
2021-04-14 10:50:43 +02:00
// properties.
2021-04-19 14:21:20 +02:00
propertyValueReader func ( properties * HiddenAPIFlagFileProperties ) [ ] string
2021-04-08 21:12:41 +02:00
2021-04-14 10:50:43 +02:00
// commandMutator adds the appropriate command line options for this category to the supplied
// command
commandMutator func ( command * android . RuleBuilderCommand , path android . Path )
}
2021-04-08 21:12:41 +02:00
2021-05-18 17:32:50 +02:00
// The flag file category for removed members of the API.
//
2021-06-09 15:39:28 +02:00
// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
2021-05-18 17:32:50 +02:00
// list of removed API members that are generated automatically from the removed.txt files provided
// by API stubs.
var hiddenAPIRemovedFlagFileCategory = & hiddenAPIFlagFileCategory {
// See HiddenAPIFlagFileProperties.Removed
2021-06-09 15:39:28 +02:00
PropertyName : "removed" ,
2021-05-18 17:32:50 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Removed
2021-05-18 17:32:50 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--unsupported " , path ) . Flag ( "--ignore-conflicts " ) . FlagWithArg ( "--tag " , "removed" )
} ,
}
2022-07-27 18:27:42 +02:00
type hiddenAPIFlagFileCategories [ ] * hiddenAPIFlagFileCategory
func ( c hiddenAPIFlagFileCategories ) byProperty ( name string ) * hiddenAPIFlagFileCategory {
for _ , category := range c {
if category . PropertyName == name {
return category
}
}
panic ( fmt . Errorf ( "no category exists with property name %q in %v" , name , c ) )
}
var HiddenAPIFlagFileCategories = hiddenAPIFlagFileCategories {
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Unsupported
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "unsupported" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Unsupported
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--unsupported " , path )
} ,
} ,
2021-05-18 17:32:50 +02:00
hiddenAPIRemovedFlagFileCategory ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Max_target_r_low_priority
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "max_target_r_low_priority" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Max_target_r_low_priority
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--max-target-r " , path ) . FlagWithArg ( "--tag " , "lo-prio" )
} ,
} ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Max_target_q
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "max_target_q" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Max_target_q
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--max-target-q " , path )
} ,
} ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Max_target_p
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "max_target_p" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Max_target_p
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--max-target-p " , path )
} ,
} ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Max_target_o_low_priority
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "max_target_o_low_priority" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Max_target_o_low_priority
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--max-target-o " , path ) . Flag ( "--ignore-conflicts " ) . FlagWithArg ( "--tag " , "lo-prio" )
} ,
} ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Blocked
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "blocked" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Blocked
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--blocked " , path )
} ,
} ,
2021-04-14 16:01:56 +02:00
// See HiddenAPIFlagFileProperties.Unsupported_packages
2021-04-14 10:50:43 +02:00
{
2021-06-09 15:39:28 +02:00
PropertyName : "unsupported_packages" ,
2021-04-19 14:21:20 +02:00
propertyValueReader : func ( properties * HiddenAPIFlagFileProperties ) [ ] string {
2022-07-27 18:16:54 +02:00
return properties . Hidden_api . Unsupported_packages
2021-04-14 10:50:43 +02:00
} ,
commandMutator : func ( command * android . RuleBuilderCommand , path android . Path ) {
command . FlagWithInput ( "--unsupported " , path ) . Flag ( "--packages " )
} ,
} ,
}
2021-05-21 17:58:23 +02:00
// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
type FlagFilesByCategory map [ * hiddenAPIFlagFileCategory ] android . Paths
2022-07-27 18:27:42 +02:00
// append the supplied flags files to the corresponding category in this map.
2021-05-21 17:58:23 +02:00
func ( s FlagFilesByCategory ) append ( other FlagFilesByCategory ) {
2021-06-09 15:39:28 +02:00
for _ , category := range HiddenAPIFlagFileCategories {
2021-05-21 17:58:23 +02:00
s [ category ] = append ( s [ category ] , other [ category ] ... )
}
}
2022-07-27 18:27:42 +02:00
// sort the paths for each category in this map.
func ( s FlagFilesByCategory ) sort ( ) {
for category , value := range s {
s [ category ] = android . SortedUniquePaths ( value )
}
}
2021-05-21 23:18:56 +02:00
// HiddenAPIInfo contains information provided by the hidden API processing.
2021-04-15 14:32:00 +02:00
//
2021-05-21 23:18:56 +02:00
// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
// processing.
type HiddenAPIInfo struct {
2021-05-21 17:58:23 +02:00
// FlagFilesByCategory maps from the flag file category to the paths containing information for
// that category.
FlagFilesByCategory FlagFilesByCategory
2021-04-15 14:32:00 +02:00
2021-06-27 21:28:29 +02:00
// The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes provided by
// this fragment and the fragments on which this depends.
TransitiveStubDexJarsByScope StubDexJarsByModule
2021-05-21 23:46:59 +02:00
2021-05-21 17:15:31 +02:00
// The output from the hidden API processing needs to be made available to other modules.
HiddenAPIFlagOutput
}
2021-04-15 14:32:00 +02:00
2021-05-17 08:38:47 +02:00
func newHiddenAPIInfo ( ) * HiddenAPIInfo {
info := HiddenAPIInfo {
2021-06-18 19:14:25 +02:00
FlagFilesByCategory : FlagFilesByCategory { } ,
2021-06-27 21:28:29 +02:00
TransitiveStubDexJarsByScope : StubDexJarsByModule { } ,
2021-05-17 08:38:47 +02:00
}
return & info
}
func ( i * HiddenAPIInfo ) mergeFromFragmentDeps ( ctx android . ModuleContext , fragments [ ] android . Module ) {
// Merge all the information from the fragments. The fragments form a DAG so it is possible that
// this will introduce duplicates so they will be resolved after processing all the fragments.
for _ , fragment := range fragments {
2023-12-13 22:47:44 +01:00
if info , ok := android . OtherModuleProvider ( ctx , fragment , HiddenAPIInfoProvider ) ; ok {
2021-06-27 21:28:29 +02:00
i . TransitiveStubDexJarsByScope . addStubDexJarsByModule ( info . TransitiveStubDexJarsByScope )
2021-05-17 08:38:47 +02:00
}
}
}
2021-08-10 17:14:16 +02:00
// StubFlagSubset returns a SignatureCsvSubset that contains a path to a filtered-stub-flags.csv
// file and a path to a signature-patterns.csv file that defines a subset of the monolithic stub
// flags file, i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
2021-07-21 18:38:47 +02:00
func ( i * HiddenAPIInfo ) StubFlagSubset ( ) SignatureCsvSubset {
2021-08-10 17:14:16 +02:00
return SignatureCsvSubset { i . FilteredStubFlagsPath , i . SignaturePatternsPath }
2021-07-21 18:38:47 +02:00
}
2021-08-10 17:14:16 +02:00
// FlagSubset returns a SignatureCsvSubset that contains a path to a filtered-flags.csv file and a
2021-07-21 18:38:47 +02:00
// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
func ( i * HiddenAPIInfo ) FlagSubset ( ) SignatureCsvSubset {
2021-08-10 17:14:16 +02:00
return SignatureCsvSubset { i . FilteredFlagsPath , i . SignaturePatternsPath }
2021-07-21 18:38:47 +02:00
}
2023-12-13 01:39:03 +01:00
var HiddenAPIInfoProvider = blueprint . NewProvider [ HiddenAPIInfo ] ( )
2021-04-15 14:32:00 +02:00
2022-09-14 17:37:12 +02:00
// HiddenAPIInfoForSdk contains information provided by the hidden API processing for use
// by the sdk snapshot.
//
// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
// processing.
type HiddenAPIInfoForSdk struct {
// FlagFilesByCategory maps from the flag file category to the paths containing information for
// that category.
FlagFilesByCategory FlagFilesByCategory
// The output from the hidden API processing needs to be made available to other modules.
HiddenAPIFlagOutput
}
// Provides hidden API info for the sdk snapshot.
2023-12-13 01:39:03 +01:00
var HiddenAPIInfoForSdkProvider = blueprint . NewProvider [ HiddenAPIInfoForSdk ] ( )
2022-09-14 17:37:12 +02:00
2021-06-27 21:28:29 +02:00
// ModuleStubDexJars contains the stub dex jars provided by a single module.
//
// It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
// hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
type ModuleStubDexJars map [ * HiddenAPIScope ] android . Path
2021-05-21 23:18:49 +02:00
2021-06-27 21:28:29 +02:00
// stubDexJarForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
2021-05-21 23:18:49 +02:00
// map.
2021-06-27 21:28:29 +02:00
//
// The relative width of APIs is determined by their order in hiddenAPIScopes.
func ( s ModuleStubDexJars ) stubDexJarForWidestAPIScope ( ) android . Path {
for i := len ( hiddenAPIScopes ) - 1 ; i >= 0 ; i -- {
apiScope := hiddenAPIScopes [ i ]
if stubsForAPIScope , ok := s [ apiScope ] ; ok {
return stubsForAPIScope
}
2021-05-21 23:18:49 +02:00
}
2021-06-27 21:28:29 +02:00
return nil
2021-05-21 23:18:49 +02:00
}
2021-06-27 21:28:29 +02:00
// StubDexJarsByModule contains the stub dex jars provided by a set of modules.
//
// It maps a module name to the path to the stub dex jars provided by that module.
type StubDexJarsByModule map [ string ] ModuleStubDexJars
// addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope.
func ( s StubDexJarsByModule ) addStubDexJar ( ctx android . ModuleContext , module android . Module , scope * HiddenAPIScope , stubDexJar android . Path ) {
name := android . RemoveOptionalPrebuiltPrefix ( module . Name ( ) )
2021-06-30 19:25:36 +02:00
// Each named module provides one dex jar for each scope. However, in some cases different API
// versions of a single classes are provided by separate modules. e.g. the core platform
// version of java.lang.Object is provided by the legacy.art.module.platform.api module but the
// public version is provided by the art.module.public.api module. In those cases it is necessary
// to treat all those modules as they were the same name, otherwise it will result in multiple
// definitions of a single class being passed to hidden API processing which will cause an error.
2023-10-06 18:54:58 +02:00
if name == scope . nonUpdatablePrebuiltModule || name == scope . nonUpdatableSourceModule || name == scope . nonUpdatableFromTextModule {
2021-06-27 21:28:29 +02:00
// Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
// java_sdk_library.
// TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
name = "android-non-updatable"
} else if name == "legacy.art.module.platform.api" {
// Treat legacy.art.module.platform.api as if it was an API scope provided by the
// art.module.public.api java_sdk_library which will be the case once the former has been
// migrated to a module_lib API.
name = "art.module.public.api"
} else if name == "legacy.i18n.module.platform.api" {
// Treat legacy.i18n.module.platform.api as if it was an API scope provided by the
// i18n.module.public.api java_sdk_library which will be the case once the former has been
// migrated to a module_lib API.
name = "i18n.module.public.api"
} else if name == "conscrypt.module.platform.api" {
// Treat conscrypt.module.platform.api as if it was an API scope provided by the
// conscrypt.module.public.api java_sdk_library which will be the case once the former has been
// migrated to a module_lib API.
name = "conscrypt.module.public.api"
2021-06-30 19:25:36 +02:00
} else if d , ok := module . ( SdkLibraryComponentDependency ) ; ok {
sdkLibraryName := d . SdkLibraryName ( )
if sdkLibraryName != nil {
// The module is a component of a java_sdk_library so use the name of the java_sdk_library.
// e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then
// use `foo` as the name.
name = * sdkLibraryName
}
2021-06-27 21:28:29 +02:00
}
stubDexJarsByScope := s [ name ]
if stubDexJarsByScope == nil {
stubDexJarsByScope = ModuleStubDexJars { }
s [ name ] = stubDexJarsByScope
2021-05-21 23:18:49 +02:00
}
2021-06-27 21:28:29 +02:00
stubDexJarsByScope [ scope ] = stubDexJar
2021-05-21 23:18:49 +02:00
}
2021-06-27 21:28:29 +02:00
// addStubDexJarsByModule adds the stub dex jars in the supplied StubDexJarsByModule to this map.
func ( s StubDexJarsByModule ) addStubDexJarsByModule ( other StubDexJarsByModule ) {
for module , stubDexJarsByScope := range other {
s [ module ] = stubDexJarsByScope
}
}
// StubDexJarsForWidestAPIScope returns a list of stub dex jars containing the widest API scope
// provided by each module.
//
// The relative width of APIs is determined by their order in hiddenAPIScopes.
func ( s StubDexJarsByModule ) StubDexJarsForWidestAPIScope ( ) android . Paths {
stubDexJars := android . Paths { }
2023-03-01 01:02:16 +01:00
modules := android . SortedKeys ( s )
2021-06-27 21:28:29 +02:00
for _ , module := range modules {
stubDexJarsByScope := s [ module ]
stubDexJars = append ( stubDexJars , stubDexJarsByScope . stubDexJarForWidestAPIScope ( ) )
}
return stubDexJars
}
// StubDexJarsForScope returns a list of stub dex jars containing the stub dex jars provided by each
// module for the specified scope.
//
// If a module does not provide a stub dex jar for the supplied scope then it does not contribute to
// the returned list.
func ( s StubDexJarsByModule ) StubDexJarsForScope ( scope * HiddenAPIScope ) android . Paths {
stubDexJars := android . Paths { }
2023-03-01 01:02:16 +01:00
modules := android . SortedKeys ( s )
2021-06-27 21:28:29 +02:00
for _ , module := range modules {
stubDexJarsByScope := s [ module ]
// Not every module will have the same set of
if jars , ok := stubDexJarsByScope [ scope ] ; ok {
stubDexJars = append ( stubDexJars , jars )
2021-05-26 11:16:01 +02:00
}
}
2021-06-27 21:28:29 +02:00
return stubDexJars
2021-05-26 11:16:01 +02:00
}
2022-07-27 17:55:06 +02:00
type HiddenAPIPropertyInfo struct {
2021-05-21 23:18:49 +02:00
// FlagFilesByCategory contains the flag files that override the initial flags that are derived
// from the stub dex files.
FlagFilesByCategory FlagFilesByCategory
2022-07-27 17:55:06 +02:00
// See HiddenAPIFlagFileProperties.Package_prefixes
PackagePrefixes [ ] string
// See HiddenAPIFlagFileProperties.Single_packages
SinglePackages [ ] string
// See HiddenAPIFlagFileProperties.Split_packages
SplitPackages [ ] string
}
2023-12-13 01:39:03 +01:00
var hiddenAPIPropertyInfoProvider = blueprint . NewProvider [ HiddenAPIPropertyInfo ] ( )
2022-07-27 18:27:42 +02:00
2022-07-27 17:55:06 +02:00
// newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
func newHiddenAPIPropertyInfo ( ) HiddenAPIPropertyInfo {
return HiddenAPIPropertyInfo {
FlagFilesByCategory : FlagFilesByCategory { } ,
}
}
// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
// supplied properties and stores them in this struct.
func ( i * HiddenAPIPropertyInfo ) extractFlagFilesFromProperties ( ctx android . ModuleContext , p * HiddenAPIFlagFileProperties ) {
for _ , category := range HiddenAPIFlagFileCategories {
paths := android . PathsForModuleSrc ( ctx , category . propertyValueReader ( p ) )
i . FlagFilesByCategory [ category ] = paths
}
}
// extractPackageRulesFromProperties extracts the package rules that are specified in the supplied
// properties and stores them in this struct.
func ( i * HiddenAPIPropertyInfo ) extractPackageRulesFromProperties ( p * HiddenAPIPackageProperties ) {
i . PackagePrefixes = p . Hidden_api . Package_prefixes
i . SinglePackages = p . Hidden_api . Single_packages
i . SplitPackages = p . Hidden_api . Split_packages
}
2022-07-27 18:27:42 +02:00
func ( i * HiddenAPIPropertyInfo ) gatherPropertyInfo ( ctx android . ModuleContext , contents [ ] android . Module ) {
for _ , module := range contents {
2023-12-13 22:47:44 +01:00
if info , ok := android . OtherModuleProvider ( ctx , module , hiddenAPIPropertyInfoProvider ) ; ok {
2022-07-27 18:27:42 +02:00
i . FlagFilesByCategory . append ( info . FlagFilesByCategory )
i . PackagePrefixes = append ( i . PackagePrefixes , info . PackagePrefixes ... )
i . SinglePackages = append ( i . SinglePackages , info . SinglePackages ... )
i . SplitPackages = append ( i . SplitPackages , info . SplitPackages ... )
}
}
// Dedup and sort the information to ensure consistent builds.
i . FlagFilesByCategory . sort ( )
i . PackagePrefixes = android . SortedUniqueStrings ( i . PackagePrefixes )
i . SinglePackages = android . SortedUniqueStrings ( i . SinglePackages )
i . SplitPackages = android . SortedUniqueStrings ( i . SplitPackages )
}
2022-07-27 17:55:06 +02:00
// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
// needed for hidden API flag generation.
type HiddenAPIFlagInput struct {
HiddenAPIPropertyInfo
2021-06-18 19:14:25 +02:00
// StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
2021-05-21 23:18:49 +02:00
// the initial flags for each dex member.
2021-06-27 21:28:29 +02:00
StubDexJarsByScope StubDexJarsByModule
2021-05-17 08:38:47 +02:00
2021-06-18 19:14:25 +02:00
// DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
// depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
2021-05-17 08:38:47 +02:00
// fragment on which this depends.
2021-06-27 21:28:29 +02:00
DependencyStubDexJarsByScope StubDexJarsByModule
2021-05-18 17:32:50 +02:00
2021-05-26 11:16:01 +02:00
// 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.
2021-06-27 21:28:29 +02:00
AdditionalStubDexJarsByScope StubDexJarsByModule
2021-05-26 11:16:01 +02:00
2021-05-18 17:32:50 +02:00
// 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
2021-05-21 23:18:49 +02:00
}
2022-07-27 17:55:06 +02:00
// newHiddenAPIFlagInput creates a new initialized HiddenAPIFlagInput struct.
2021-05-21 23:18:49 +02:00
func newHiddenAPIFlagInput ( ) HiddenAPIFlagInput {
input := HiddenAPIFlagInput {
2022-07-27 17:55:06 +02:00
HiddenAPIPropertyInfo : newHiddenAPIPropertyInfo ( ) ,
2021-06-27 21:28:29 +02:00
StubDexJarsByScope : StubDexJarsByModule { } ,
DependencyStubDexJarsByScope : StubDexJarsByModule { } ,
AdditionalStubDexJarsByScope : StubDexJarsByModule { } ,
2021-05-21 23:18:49 +02:00
}
return input
}
// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
// dependencies added in hiddenAPIAddStubLibDependencies.
//
// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
func ( i * HiddenAPIFlagInput ) gatherStubLibInfo ( ctx android . ModuleContext , contents [ ] android . Module ) {
2021-06-18 19:14:25 +02:00
addFromModule := func ( ctx android . ModuleContext , module android . Module , apiScope * HiddenAPIScope ) {
sdkKind := apiScope . sdkKind
dexJar := hiddenAPIRetrieveDexJarBuildPath ( ctx , module , sdkKind )
2021-05-21 23:18:49 +02:00
if dexJar != nil {
2021-06-27 21:28:29 +02:00
i . StubDexJarsByScope . addStubDexJar ( ctx , module , apiScope , dexJar )
2021-05-21 23:18:49 +02:00
}
2021-05-18 17:32:50 +02:00
if sdkLibrary , ok := module . ( SdkLibraryDependency ) ; ok {
2021-06-18 19:14:25 +02:00
removedTxtFile := sdkLibrary . SdkRemovedTxtFile ( ctx , sdkKind )
2021-05-18 17:32:50 +02:00
i . RemovedTxtFiles = append ( i . RemovedTxtFiles , removedTxtFile . AsPaths ( ) ... )
}
2021-05-21 23:18:49 +02:00
}
// If the contents includes any java_sdk_library modules then add them to the stubs.
for _ , module := range contents {
if _ , ok := module . ( SdkLibraryDependency ) ; ok {
2021-06-18 19:14:25 +02:00
// Add information for every possible API scope needed by hidden API.
for _ , apiScope := range hiddenAPISdkLibrarySupportedScopes {
addFromModule ( ctx , module , apiScope )
2021-05-21 23:18:49 +02:00
}
}
}
2021-06-07 22:36:01 +02:00
ctx . VisitDirectDeps ( func ( module android . Module ) {
2021-05-21 23:18:49 +02:00
tag := ctx . OtherModuleDependencyTag ( module )
if hiddenAPIStubsTag , ok := tag . ( hiddenAPIStubsDependencyTag ) ; ok {
2021-06-18 19:14:25 +02:00
apiScope := hiddenAPIStubsTag . apiScope
2021-05-26 11:16:01 +02:00
if hiddenAPIStubsTag . fromAdditionalDependency {
dexJar := hiddenAPIRetrieveDexJarBuildPath ( ctx , module , apiScope . sdkKind )
if dexJar != nil {
2021-06-27 21:28:29 +02:00
i . AdditionalStubDexJarsByScope . addStubDexJar ( ctx , module , apiScope , dexJar )
2021-05-26 11:16:01 +02:00
}
} else {
addFromModule ( ctx , module , apiScope )
}
2021-05-21 23:18:49 +02:00
}
} )
// Normalize the paths, i.e. remove duplicates and sort.
2021-05-18 17:32:50 +02:00
i . RemovedTxtFiles = android . SortedUniquePaths ( i . RemovedTxtFiles )
2021-05-21 23:18:49 +02:00
}
2021-06-27 21:28:29 +02:00
func ( i * HiddenAPIFlagInput ) transitiveStubDexJarsByScope ( ) StubDexJarsByModule {
2021-06-18 19:14:25 +02:00
transitive := i . DependencyStubDexJarsByScope
2021-06-27 21:28:29 +02:00
transitive . addStubDexJarsByModule ( i . StubDexJarsByScope )
2021-05-17 08:38:47 +02:00
return transitive
}
2021-05-21 17:15:31 +02:00
// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
// bootclasspath_fragment module.
type HiddenAPIFlagOutput struct {
// The path to the generated annotation-flags.csv file.
AnnotationFlagsPath android . Path
2021-04-15 14:32:00 +02:00
2021-05-21 17:15:31 +02:00
// The path to the generated metadata.csv file.
MetadataPath android . Path
2021-04-08 21:12:41 +02:00
2021-05-21 17:15:31 +02:00
// The path to the generated index.csv file.
IndexPath android . Path
2021-08-10 17:14:16 +02:00
// The path to the generated stub-flags.csv file.
StubFlagsPath android . Path
2021-05-21 17:15:31 +02:00
// The path to the generated all-flags.csv file.
AllFlagsPath android . Path
2021-07-21 18:38:47 +02:00
// The path to the generated signature-patterns.txt file which defines the subset of the
// monolithic hidden API files provided in this.
SignaturePatternsPath android . Path
2021-08-10 17:14:16 +02:00
// The path to the generated filtered-stub-flags.csv file.
FilteredStubFlagsPath android . Path
// The path to the generated filtered-flags.csv file.
FilteredFlagsPath android . Path
2021-05-21 17:15:31 +02:00
}
2021-04-09 00:01:37 +02:00
2021-06-02 18:24:22 +02:00
// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
// path.
type bootDexJarByModule map [ string ] android . Path
// addPath adds the path for a module to the map.
func ( b bootDexJarByModule ) addPath ( module android . Module , path android . Path ) {
b [ android . RemoveOptionalPrebuiltPrefix ( module . Name ( ) ) ] = path
}
2021-06-07 14:28:19 +02:00
// bootDexJars returns the boot dex jar paths sorted by their keys.
func ( b bootDexJarByModule ) bootDexJars ( ) android . Paths {
paths := android . Paths { }
2023-03-01 01:02:16 +01:00
for _ , k := range android . SortedKeys ( b ) {
2021-06-07 14:28:19 +02:00
paths = append ( paths , b [ k ] )
}
return paths
}
2021-06-17 20:33:24 +02:00
// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
// libraries if present.
func ( b bootDexJarByModule ) bootDexJarsWithoutCoverage ( ) android . Paths {
paths := android . Paths { }
2023-03-01 01:02:16 +01:00
for _ , k := range android . SortedKeys ( b ) {
2021-06-17 20:33:24 +02:00
if k == "jacocoagent" {
continue
}
paths = append ( paths , b [ k ] )
}
return paths
}
2021-06-07 14:28:19 +02:00
// HiddenAPIOutput encapsulates the output from the hidden API processing.
type HiddenAPIOutput struct {
HiddenAPIFlagOutput
// The map from base module name to the path to the encoded boot dex file.
2023-12-13 01:06:32 +01:00
// This field is not available in prebuilt apexes
2021-06-07 14:28:19 +02:00
EncodedBootDexFilesByModule bootDexJarByModule
}
2021-05-13 18:31:51 +02:00
// pathForValidation creates a path of the same type as the supplied type but with a name of
// <path>.valid.
//
// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
func pathForValidation ( ctx android . PathContext , path android . WritablePath ) android . WritablePath {
extWithoutLeadingDot := strings . TrimPrefix ( path . Ext ( ) , "." )
return path . ReplaceExtension ( ctx , extWithoutLeadingDot + ".valid" )
}
2021-04-15 14:32:00 +02:00
// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
// the flags from all the modules, the stub flags, augmented with some additional configuration
// files.
2021-04-08 21:12:41 +02:00
//
// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
// an entry for every single member in the dex implementation jars of the individual modules. Every
// signature in any of the other files MUST be included in this file.
//
2021-05-14 11:38:00 +02:00
// annotationFlags is the path to the annotation flags file generated from annotation information
// in each module.
2021-04-08 21:12:41 +02:00
//
2021-05-21 23:18:56 +02:00
// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
2021-05-14 11:38:00 +02:00
// the annotationFlags.
2021-05-18 17:32:50 +02:00
func buildRuleToGenerateHiddenApiFlags ( ctx android . BuilderContext , name , desc string ,
2021-06-07 22:36:01 +02:00
outputPath android . WritablePath , baseFlagsPath android . Path , annotationFlagPaths android . Paths ,
2021-07-21 18:38:47 +02:00
flagFilesByCategory FlagFilesByCategory , flagSubsets SignatureCsvSubsets , generatedRemovedDexSignatures android . OptionalPath ) {
2021-05-13 18:31:51 +02:00
// Create the rule that will generate the flag files.
2021-04-21 23:12:35 +02:00
tempPath := tempPathForRestat ( ctx , outputPath )
2021-04-08 21:12:41 +02:00
rule := android . NewRuleBuilder ( pctx , ctx )
command := rule . Command ( ) .
BuiltTool ( "generate_hiddenapi_lists" ) .
FlagWithInput ( "--csv " , baseFlagsPath ) .
2021-06-07 22:36:01 +02:00
Inputs ( annotationFlagPaths ) .
2021-04-08 21:12:41 +02:00
FlagWithOutput ( "--output " , tempPath )
2021-04-14 10:50:43 +02:00
// Add the options for the different categories of flag files.
2021-06-09 15:39:28 +02:00
for _ , category := range HiddenAPIFlagFileCategories {
2021-05-21 17:58:23 +02:00
paths := flagFilesByCategory [ category ]
2021-04-14 10:50:43 +02:00
for _ , path := range paths {
category . commandMutator ( command , path )
}
2021-04-08 21:12:41 +02:00
}
2021-05-18 17:32:50 +02:00
// If available then pass the automatically generated file containing dex signatures of removed
// API members to the rule so they can be marked as removed.
if generatedRemovedDexSignatures . Valid ( ) {
hiddenAPIRemovedFlagFileCategory . commandMutator ( command , generatedRemovedDexSignatures . Path ( ) )
}
2021-04-08 21:12:41 +02:00
commitChangeForRestat ( rule , tempPath , outputPath )
2021-06-24 00:29:09 +02:00
// If there are flag files that have been generated by fragments on which this depends then use
// them to validate the flag file generated by the rules created by this method.
2023-11-01 14:58:39 +01:00
if ! ctx . Config ( ) . DisableVerifyOverlaps ( ) && len ( flagSubsets ) > 0 {
2022-04-08 00:32:19 +02:00
validFile := buildRuleValidateOverlappingCsvFiles ( ctx , name , desc , outputPath , flagSubsets ,
HIDDENAPI_FLAGS_CSV_IMPL_FLAGS )
2021-06-24 00:29:09 +02:00
2021-05-13 18:31:51 +02:00
// Add the file that indicates that the file generated by this is valid.
//
// This will cause the validation rule above to be run any time that the output of this rule
// changes but the validation will run in parallel with other rules that depend on this file.
command . Validation ( validFile )
}
2021-04-15 14:32:00 +02:00
rule . Build ( name , desc )
}
2021-07-21 18:38:47 +02:00
// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
type SignatureCsvSubset struct {
// The path to the CSV file containing hidden API flags.
//
// It has the dex member signature as the first column, with flags, one per column, in the
// subsequent columns.
CsvFile android . Path
// The path to the CSV file containing the signature patterns.
//
// It is a single column CSV file with the column containing a signature pattern.
SignaturePatternsFile android . Path
}
type SignatureCsvSubsets [ ] SignatureCsvSubset
func ( s SignatureCsvSubsets ) RelativeToTop ( ) [ ] string {
result := [ ] string { }
for _ , subset := range s {
result = append ( result , fmt . Sprintf ( "%s:%s" , subset . CsvFile . RelativeToTop ( ) , subset . SignaturePatternsFile . RelativeToTop ( ) ) )
}
return result
}
// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
// patterns that will select a subset of the monolithic flags.
2022-03-15 18:45:57 +01:00
func buildRuleSignaturePatternsFile (
ctx android . ModuleContext , flagsPath android . Path ,
2022-07-27 01:53:00 +02:00
splitPackages [ ] string , packagePrefixes [ ] string , singlePackages [ ] string ,
suffix string ) android . Path {
hiddenApiSubDir := "modular-hiddenapi" + suffix
patternsFile := android . PathForModuleOut ( ctx , hiddenApiSubDir , "signature-patterns.csv" )
2021-07-21 18:38:47 +02:00
// Create a rule to validate the output from the following rule.
rule := android . NewRuleBuilder ( pctx , ctx )
2021-08-03 16:42:27 +02:00
// Quote any * in the packages to avoid them being expanded by the shell.
quotedSplitPackages := [ ] string { }
for _ , pkg := range splitPackages {
quotedSplitPackages = append ( quotedSplitPackages , strings . ReplaceAll ( pkg , "*" , "\\*" ) )
}
2021-07-21 18:38:47 +02:00
rule . Command ( ) .
BuiltTool ( "signature_patterns" ) .
FlagWithInput ( "--flags " , flagsPath ) .
2021-08-03 16:42:27 +02:00
FlagForEachArg ( "--split-package " , quotedSplitPackages ) .
FlagForEachArg ( "--package-prefix " , packagePrefixes ) .
2022-03-15 18:45:57 +01:00
FlagForEachArg ( "--single-package " , singlePackages ) .
2021-07-21 18:38:47 +02:00
FlagWithOutput ( "--output " , patternsFile )
2022-07-27 01:53:00 +02:00
rule . Build ( "hiddenAPISignaturePatterns" + suffix , "hidden API signature patterns" + suffix )
2021-07-21 18:38:47 +02:00
return patternsFile
}
2022-04-08 00:32:19 +02:00
// buildRuleRemoveSignaturesWithImplementationFlags creates a rule that will remove signatures from
// the input flags file which have only the implementation flags, i.e. are not part of an API.
//
// The implementationFlags specifies the set of default flags that identifies the signature of a
// private, implementation only, member. Signatures that match those flags are removed from the
// flags as they are implementation only.
//
// This is used to remove implementation only signatures from the signature files that are persisted
// in the sdk snapshot as the sdk snapshots should not include implementation details. The
// signatures generated by this method will be compared by the buildRuleValidateOverlappingCsvFiles
// method which treats any missing signatures as if they were implementation only signatures.
func buildRuleRemoveSignaturesWithImplementationFlags ( ctx android . BuilderContext ,
name string , desc string , inputPath android . Path , filteredPath android . WritablePath ,
implementationFlags [ ] string ) {
2021-07-20 19:03:53 +02:00
rule := android . NewRuleBuilder ( pctx , ctx )
2022-04-08 00:32:19 +02:00
implementationFlagPattern := ""
for _ , implementationFlag := range implementationFlags {
implementationFlagPattern = implementationFlagPattern + "," + implementationFlag
}
2021-07-20 19:03:53 +02:00
rule . Command ( ) .
2022-04-08 00:32:19 +02:00
Text ( ` grep -vE "^[^,]+ ` + implementationFlagPattern + ` $" ` ) . Input ( inputPath ) .
Text ( ">" ) . Output ( filteredPath ) .
2021-07-20 19:03:53 +02:00
// Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
// something and 1 (build failure) when it does not and 2 (when it encounters an error).
// However, while it is unlikely it is not an error if this does not find any matches. The
// following will only run if the grep does not find something and in that case it will treat
// an exit code of 1 as success and anything else as failure.
Text ( "|| test $? -eq 1" )
rule . Build ( name , desc )
}
2021-06-24 00:29:09 +02:00
// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
2022-04-08 00:32:19 +02:00
//
// The implementationFlags specifies the set of default flags that identifies the signature of a
// private, implementation only, member. A signature which is present in a monolithic flags subset
// defined by SignatureCsvSubset but which is not present in the flags file from the corresponding
// module is assumed to be an implementation only member and so must have these flags.
func buildRuleValidateOverlappingCsvFiles ( ctx android . BuilderContext , name string , desc string ,
monolithicFilePath android . WritablePath , csvSubsets SignatureCsvSubsets ,
implementationFlags [ ] string ) android . WritablePath {
2021-06-24 00:29:09 +02:00
// The file which is used to record that the flags file is valid.
validFile := pathForValidation ( ctx , monolithicFilePath )
// Create a rule to validate the output from the following rule.
rule := android . NewRuleBuilder ( pctx , ctx )
2021-07-21 18:38:47 +02:00
command := rule . Command ( ) .
2021-06-24 00:29:09 +02:00
BuiltTool ( "verify_overlaps" ) .
2022-04-08 01:28:11 +02:00
FlagWithInput ( "--monolithic-flags " , monolithicFilePath )
2021-07-21 18:38:47 +02:00
for _ , subset := range csvSubsets {
command .
2022-04-08 01:28:11 +02:00
Flag ( "--module-flags " ) .
2021-07-21 18:38:47 +02:00
Textf ( "%s:%s" , subset . CsvFile , subset . SignaturePatternsFile ) .
Implicit ( subset . CsvFile ) . Implicit ( subset . SignaturePatternsFile )
}
2022-04-08 00:32:19 +02:00
for _ , implementationFlag := range implementationFlags {
command . FlagWithArg ( "--implementation-flag " , implementationFlag )
}
2021-07-21 18:38:47 +02:00
// If validation passes then update the file that records that.
command . Text ( "&& touch" ) . Output ( validFile )
2021-06-24 00:29:09 +02:00
rule . Build ( name + "Validation" , desc + " validation" )
return validFile
}
2022-09-14 12:47:34 +02:00
// hiddenAPIFlagRulesForBootclasspathFragment will generate all the flags for a fragment of the
// bootclasspath.
2021-04-15 14:32:00 +02:00
//
// It takes:
// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
// * The list of modules that are the contents of the fragment.
// * The additional manually curated flag files to use.
//
// It generates:
// * stub-flags.csv
// * annotation-flags.csv
// * metadata.csv
// * index.csv
// * all-flags.csv
2022-07-27 01:53:00 +02:00
func hiddenAPIFlagRulesForBootclasspathFragment ( ctx android . ModuleContext , bootDexInfoByModule bootDexInfoByModule , contents [ ] android . Module , input HiddenAPIFlagInput , suffix string ) HiddenAPIFlagOutput {
hiddenApiSubDir := "modular-hiddenapi" + suffix
2021-04-15 14:32:00 +02:00
2021-05-21 23:18:49 +02:00
// Generate the stub-flags.csv.
2021-04-15 14:32:00 +02:00
stubFlagsCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "stub-flags.csv" )
2022-07-27 01:53:00 +02:00
buildRuleToGenerateHiddenAPIStubFlagsFile ( ctx , "modularHiddenAPIStubFlagsFile" + suffix , "modular hiddenapi stub flags" , stubFlagsCSV , bootDexInfoByModule . bootDexJars ( ) , input , nil )
2021-04-15 14:32:00 +02:00
2021-05-14 11:38:00 +02:00
// Extract the classes jars from the contents.
2021-06-10 11:18:22 +02:00
classesJars := extractClassesJarsFromModules ( contents )
2021-05-14 11:38:00 +02:00
2021-04-15 14:32:00 +02:00
// Generate the set of flags from the annotations in the source code.
annotationFlagsCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "annotation-flags.csv" )
2022-07-27 01:53:00 +02:00
buildRuleToGenerateAnnotationFlags ( ctx , "modular hiddenapi annotation flags" + suffix , classesJars , stubFlagsCSV , annotationFlagsCSV )
2021-04-15 14:32:00 +02:00
// Generate the metadata from the annotations in the source code.
metadataCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "metadata.csv" )
2022-07-27 01:53:00 +02:00
buildRuleToGenerateMetadata ( ctx , "modular hiddenapi metadata" + suffix , classesJars , stubFlagsCSV , metadataCSV )
2021-04-15 14:32:00 +02:00
2021-05-14 11:38:00 +02:00
// Generate the index file from the CSV files in the classes jars.
2021-04-15 14:32:00 +02:00
indexCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "index.csv" )
2022-07-27 01:53:00 +02:00
buildRuleToGenerateIndex ( ctx , "modular hiddenapi index" + suffix , classesJars , indexCSV )
2021-04-15 14:32:00 +02:00
2021-05-21 23:18:56 +02:00
// Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
2021-04-15 14:32:00 +02:00
// containing dex signatures of all the removed APIs. In the monolithic files that is done by
// manually combining all the removed.txt files for each API and then converting them to dex
2021-05-18 17:32:50 +02:00
// signatures, see the combined-removed-dex module. This does that automatically by using the
// *removed.txt files retrieved from the java_sdk_library modules that are specified in the
// stub_libs and contents properties of a bootclasspath_fragment.
2022-07-27 01:53:00 +02:00
removedDexSignatures := buildRuleToGenerateRemovedDexSignatures ( ctx , suffix , input . RemovedTxtFiles )
2021-04-15 14:32:00 +02:00
// Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
// files.
2021-06-07 14:28:19 +02:00
allFlagsCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "all-flags.csv" )
2022-07-27 01:53:00 +02:00
buildRuleToGenerateHiddenApiFlags ( ctx , "modularHiddenApiAllFlags" + suffix , "modular hiddenapi all flags" + suffix , allFlagsCSV , stubFlagsCSV , android . Paths { annotationFlagsCSV } , input . FlagFilesByCategory , nil , removedDexSignatures )
2021-06-07 14:28:19 +02:00
2021-07-20 19:03:53 +02:00
// Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
// compared against the monolithic stub flags.
filteredStubFlagsCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "filtered-stub-flags.csv" )
2022-07-27 01:53:00 +02:00
buildRuleRemoveSignaturesWithImplementationFlags ( ctx , "modularHiddenApiFilteredStubFlags" + suffix ,
"modular hiddenapi filtered stub flags" + suffix , stubFlagsCSV , filteredStubFlagsCSV ,
2022-04-08 00:32:19 +02:00
HIDDENAPI_STUB_FLAGS_IMPL_FLAGS )
2021-07-20 19:03:53 +02:00
// Generate the filtered-flags.csv file which contains the filtered flags that will be compared
// against the monolithic flags.
filteredFlagsCSV := android . PathForModuleOut ( ctx , hiddenApiSubDir , "filtered-flags.csv" )
2022-07-27 01:53:00 +02:00
buildRuleRemoveSignaturesWithImplementationFlags ( ctx , "modularHiddenApiFilteredFlags" + suffix ,
"modular hiddenapi filtered flags" + suffix , allFlagsCSV , filteredFlagsCSV ,
2022-04-08 00:32:19 +02:00
HIDDENAPI_FLAGS_CSV_IMPL_FLAGS )
2021-07-20 19:03:53 +02:00
2021-04-15 14:32:00 +02:00
// Store the paths in the info for use by other modules and sdk snapshot generation.
2022-09-14 12:47:34 +02:00
return HiddenAPIFlagOutput {
AnnotationFlagsPath : annotationFlagsCSV ,
MetadataPath : metadataCSV ,
IndexPath : indexCSV ,
StubFlagsPath : stubFlagsCSV ,
AllFlagsPath : allFlagsCSV ,
FilteredStubFlagsPath : filteredStubFlagsCSV ,
FilteredFlagsPath : filteredFlagsCSV ,
}
}
// hiddenAPIEncodeRulesForBootclasspathFragment generates rules to encode hidden API flags into the
// dex jars in bootDexInfoByModule.
func hiddenAPIEncodeRulesForBootclasspathFragment ( ctx android . ModuleContext , bootDexInfoByModule bootDexInfoByModule , allFlagsCSV android . Path ) bootDexJarByModule {
// Encode the flags into the boot dex files.
encodedBootDexJarsByModule := bootDexJarByModule { }
outputDir := android . PathForModuleOut ( ctx , "hiddenapi-modular/encoded" ) . OutputPath
2023-03-01 01:02:16 +01:00
for _ , name := range android . SortedKeys ( bootDexInfoByModule ) {
2022-09-14 12:47:34 +02:00
bootDexInfo := bootDexInfoByModule [ name ]
unencodedDex := bootDexInfo . path
encodedDex := hiddenAPIEncodeDex ( ctx , unencodedDex , allFlagsCSV , bootDexInfo . uncompressDex , bootDexInfo . minSdkVersion , outputDir )
encodedBootDexJarsByModule [ name ] = encodedDex
2021-05-21 17:15:31 +02:00
}
2022-09-14 12:47:34 +02:00
return encodedBootDexJarsByModule
2021-04-08 21:12:41 +02:00
}
2021-05-14 11:38:00 +02:00
2022-07-27 01:53:00 +02:00
func buildRuleToGenerateRemovedDexSignatures ( ctx android . ModuleContext , suffix string , removedTxtFiles android . Paths ) android . OptionalPath {
2021-05-18 17:32:50 +02:00
if len ( removedTxtFiles ) == 0 {
return android . OptionalPath { }
}
2022-07-27 01:53:00 +02:00
output := android . PathForModuleOut ( ctx , "module-hiddenapi" + suffix , "removed-dex-signatures.txt" )
2021-05-18 17:32:50 +02:00
rule := android . NewRuleBuilder ( pctx , ctx )
rule . Command ( ) .
BuiltTool ( "metalava" ) .
Inputs ( removedTxtFiles ) .
FlagWithOutput ( "--dex-api " , output )
2022-07-27 01:53:00 +02:00
rule . Build ( "modular-hiddenapi-removed-dex-signatures" + suffix , "modular hiddenapi removed dex signatures" + suffix )
2021-05-18 17:32:50 +02:00
return android . OptionalPathForPath ( output )
}
2021-06-10 11:18:22 +02:00
// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
2021-06-07 14:28:19 +02:00
func extractBootDexJarsFromModules ( ctx android . ModuleContext , contents [ ] android . Module ) bootDexJarByModule {
bootDexJars := bootDexJarByModule { }
2021-05-14 11:38:00 +02:00
for _ , module := range contents {
2021-06-10 11:18:22 +02:00
hiddenAPIModule := hiddenAPIModuleFromModule ( ctx , module )
if hiddenAPIModule == nil {
continue
}
2021-06-07 14:28:19 +02:00
bootDexJar := retrieveBootDexJarFromHiddenAPIModule ( ctx , hiddenAPIModule )
bootDexJars . addPath ( module , bootDexJar )
2021-05-14 11:38:00 +02:00
}
return bootDexJars
}
2021-06-10 11:18:22 +02:00
func hiddenAPIModuleFromModule ( ctx android . BaseModuleContext , module android . Module ) hiddenAPIModule {
if hiddenAPIModule , ok := module . ( hiddenAPIModule ) ; ok {
return hiddenAPIModule
} else if _ , ok := module . ( * DexImport ) ; ok {
// Ignore this for the purposes of hidden API processing
} else {
ctx . ModuleErrorf ( "module %s does not implement hiddenAPIModule" , module )
}
return nil
}
2021-06-07 14:28:19 +02:00
// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
type bootDexInfo struct {
// The path to the dex jar that has not had hidden API flags encoded into it.
path android . Path
// Indicates whether the dex jar needs uncompressing before encoding.
uncompressDex bool
2022-04-28 18:45:11 +02:00
// The minimum sdk version that the dex jar will be used on.
2023-03-03 22:20:36 +01:00
minSdkVersion android . ApiLevel
2021-06-07 14:28:19 +02:00
}
// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
type bootDexInfoByModule map [ string ] bootDexInfo
// bootDexJars returns the boot dex jar paths sorted by their keys.
func ( b bootDexInfoByModule ) bootDexJars ( ) android . Paths {
paths := android . Paths { }
2023-03-01 01:02:16 +01:00
for _ , m := range android . SortedKeys ( b ) {
2021-06-07 14:28:19 +02:00
paths = append ( paths , b [ m ] . path )
}
return paths
}
// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
// each of the supplied modules which must implement hiddenAPIModule.
func extractBootDexInfoFromModules ( ctx android . ModuleContext , contents [ ] android . Module ) bootDexInfoByModule {
bootDexJarsByModule := bootDexInfoByModule { }
for _ , module := range contents {
hiddenAPIModule := module . ( hiddenAPIModule )
bootDexJar := retrieveBootDexJarFromHiddenAPIModule ( ctx , hiddenAPIModule )
bootDexJarsByModule [ module . Name ( ) ] = bootDexInfo {
path : bootDexJar ,
uncompressDex : * hiddenAPIModule . uncompressDex ( ) ,
2022-04-28 18:45:11 +02:00
minSdkVersion : hiddenAPIModule . MinSdkVersion ( ctx ) ,
2021-06-07 14:28:19 +02:00
}
}
return bootDexJarsByModule
}
// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
//
2021-09-15 04:34:04 +02:00
// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or
// invalid, then create a fake path and either report an error immediately or defer reporting of the
// error until the path is actually used.
2021-06-07 14:28:19 +02:00
func retrieveBootDexJarFromHiddenAPIModule ( ctx android . ModuleContext , module hiddenAPIModule ) android . Path {
bootDexJar := module . bootDexJar ( )
2021-09-15 04:34:04 +02:00
if ! bootDexJar . Valid ( ) {
2021-06-07 14:28:19 +02:00
fake := android . PathForModuleOut ( ctx , fmt . Sprintf ( "fake/boot-dex/%s.jar" , module . Name ( ) ) )
2021-09-15 04:34:04 +02:00
handleMissingDexBootFile ( ctx , module , fake , bootDexJar . InvalidReason ( ) )
return fake
2021-06-07 14:28:19 +02:00
}
2021-09-15 04:34:04 +02:00
return bootDexJar . Path ( )
2021-06-07 14:28:19 +02:00
}
2021-06-10 11:18:22 +02:00
// extractClassesJarsFromModules extracts the class jars from the supplied modules.
func extractClassesJarsFromModules ( contents [ ] android . Module ) android . Paths {
2021-05-14 11:38:00 +02:00
classesJars := android . Paths { }
for _ , module := range contents {
2021-06-10 11:18:22 +02:00
classesJars = append ( classesJars , retrieveClassesJarsFromModule ( module ) ... )
2021-05-14 11:38:00 +02:00
}
return classesJars
}
2021-06-02 18:24:22 +02:00
2021-06-10 11:18:22 +02:00
// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
func retrieveClassesJarsFromModule ( module android . Module ) android . Paths {
if hiddenAPIModule , ok := module . ( hiddenAPIModule ) ; ok {
return hiddenAPIModule . classesJars ( )
}
return nil
}
2021-06-02 18:24:22 +02:00
// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
// Soong but should instead only be reported in ninja if the file is actually built.
func deferReportingMissingBootDexJar ( ctx android . ModuleContext , module android . Module ) bool {
2021-06-07 14:28:19 +02:00
// Any missing dependency should be allowed.
if ctx . Config ( ) . AllowMissingDependencies ( ) {
return true
}
2021-06-02 18:24:22 +02:00
// This is called for both platform_bootclasspath and bootclasspath_fragment modules.
//
// A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
// Ideally, a bootclasspath_fragment module should never have a platform variant created for it
// but unfortunately, due to b/187910671 it does.
//
// That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
// used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
// has an APEX variant not a platform variant.
//
// There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
// provide a boot dex jar:
// 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
// does not have an APEX variant and only has a platform variant and neither do its content
// modules.
// 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
// java_sdk_library_import modules to be treated as preferred and as many of them are not part
// of an apex they cannot provide a boot dex jar.
//
// The first case causes problems when the affected prebuilt modules are preferred but that is an
// invalid configuration and it is ok for it to fail as the work to enable that is not yet
// complete. The second case is used for building targets that do not use boot dex jars and so
// deferring error reporting to ninja is fine as the affected ninja targets should never be built.
// That is handled above.
//
// A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
// the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
// can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
// that if the library can be part of an APEX then it is the APEX variant that is used.
//
// This check handles the slightly different requirements of the bootclasspath_fragment and
// platform_bootclasspath modules by only deferring error reporting for the platform variant of
// a prebuilt modules that has other variants which are part of an APEX.
//
// TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
if android . IsModulePrebuilt ( module ) {
2021-06-29 14:36:34 +02:00
// An inactive source module can still contribute to the APEX but an inactive prebuilt module
// should not contribute to anything. So, rather than have a missing dex jar cause a Soong
// failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly
// built Ninja should never use the dex jar file.
if ! isActiveModule ( module ) {
return true
}
2021-06-02 18:24:22 +02:00
if am , ok := module . ( android . ApexModule ) ; ok && am . InAnyApex ( ) {
2023-12-13 22:47:44 +01:00
apexInfo , _ := android . OtherModuleProvider ( ctx , module , android . ApexInfoProvider )
2021-06-02 18:24:22 +02:00
if apexInfo . IsForPlatform ( ) {
return true
}
}
}
return false
}
// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
// file depending on the value returned from deferReportingMissingBootDexJar.
2021-09-15 04:34:04 +02:00
func handleMissingDexBootFile ( ctx android . ModuleContext , module android . Module , fake android . WritablePath , reason string ) {
2021-06-02 18:24:22 +02:00
if deferReportingMissingBootDexJar ( ctx , module ) {
// Create an error rule that pretends to create the output file but will actually fail if it
// is run.
ctx . Build ( pctx , android . BuildParams {
Rule : android . ErrorRule ,
Output : fake ,
Args : map [ string ] string {
2021-09-15 04:34:04 +02:00
"error" : fmt . Sprintf ( "missing boot dex jar dependency for %s: %s" , module , reason ) ,
2021-06-02 18:24:22 +02:00
} ,
} )
} else {
2021-09-15 04:34:04 +02:00
ctx . ModuleErrorf ( "module %s does not provide a dex jar: %s" , module , reason )
2021-06-02 18:24:22 +02:00
}
}
// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
// DexJarBuildPath() method.
//
// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
// However, under certain conditions, e.g. errors, or special build configurations it will return
// a path to a fake file.
func retrieveEncodedBootDexJarFromModule ( ctx android . ModuleContext , module android . Module ) android . Path {
2021-09-15 04:34:04 +02:00
bootDexJar := module . ( interface { DexJarBuildPath ( ) OptionalDexJarPath } ) . DexJarBuildPath ( )
if ! bootDexJar . Valid ( ) {
2021-06-02 18:24:22 +02:00
fake := android . PathForModuleOut ( ctx , fmt . Sprintf ( "fake/encoded-dex/%s.jar" , module . Name ( ) ) )
2021-09-15 04:34:04 +02:00
handleMissingDexBootFile ( ctx , module , fake , bootDexJar . InvalidReason ( ) )
return fake
2021-06-02 18:24:22 +02:00
}
2021-09-15 04:34:04 +02:00
return bootDexJar . Path ( )
2021-06-02 18:24:22 +02:00
}
// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
func extractEncodedDexJarsFromModules ( ctx android . ModuleContext , contents [ ] android . Module ) bootDexJarByModule {
encodedDexJarsByModuleName := bootDexJarByModule { }
for _ , module := range contents {
path := retrieveEncodedBootDexJarFromModule ( ctx , module )
encodedDexJarsByModuleName . addPath ( module , path )
}
return encodedDexJarsByModuleName
}