blob: 8a0d6349ef19fda1a5fb5c54af7ab18883d29837 [file] [log] [blame]
Paul Duffinc6bb7cf2021-04-08 17:49:27 +01001// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
Paul Duffin59db6d42021-05-19 09:36:09 +010018 "fmt"
Paul Duffindfa10832021-05-13 17:31:51 +010019 "strings"
20
Paul Duffinc6bb7cf2021-04-08 17:49:27 +010021 "android/soong/android"
Paul Duffin9b381ef2021-04-08 23:01:37 +010022 "github.com/google/blueprint"
Paul Duffin699a0042021-05-23 16:55:37 +010023 "github.com/google/blueprint/proptools"
Paul Duffinc6bb7cf2021-04-08 17:49:27 +010024)
25
26// Contains support for processing hiddenAPI in a modular fashion.
27
Paul Duffin05bbff92021-06-18 18:14:25 +010028// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API
29// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do
30// not provide the information needed by hidden API processing.
31type HiddenAPIScope struct {
32 // The name of the scope, used for debug purposes.
33 name string
34
35 // The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules.
36 sdkKind android.SdkKind
37
38 // The option needed to passed to "hiddenapi list".
39 hiddenAPIListOption string
40}
41
42// initHiddenAPIScope initializes the scope.
43func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
44 return apiScope
45}
46
47func (l *HiddenAPIScope) String() string {
48 return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
49}
50
51var (
52 PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
53 name: "public",
54 sdkKind: android.SdkPublic,
55 hiddenAPIListOption: "--public-stub-classpath",
56 })
57 SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
58 name: "system",
59 sdkKind: android.SdkSystem,
60 hiddenAPIListOption: "--system-stub-classpath",
61 })
62 TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
63 name: "test",
64 sdkKind: android.SdkTest,
65 hiddenAPIListOption: "--test-stub-classpath",
66 })
Paul Duffin2cb06b72021-06-21 14:08:08 +010067 ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
68 name: "module-lib",
69 sdkKind: android.SdkModule,
70 })
Paul Duffin05bbff92021-06-18 18:14:25 +010071 CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
72 name: "core-platform",
73 sdkKind: android.SdkCorePlatform,
74 hiddenAPIListOption: "--core-platform-stub-classpath",
75 })
76
77 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
78 // API processing.
79 //
80 // These are roughly in order from narrowest API surface to widest. Widest means the API stubs
81 // with the biggest API surface, e.g. test is wider than system is wider than public.
82 //
Paul Duffin2cb06b72021-06-21 14:08:08 +010083 // Core platform is considered wider than system/module-lib because those modules that provide
84 // core platform APIs either do not have any system/module-lib APIs at all, or if they do it is
85 // because the core platform API is being converted to system/module-lib APIs. In either case the
86 // system/module-lib APIs are subsets of the core platform API.
Paul Duffin05bbff92021-06-18 18:14:25 +010087 //
88 // This is not strictly in order from narrowest to widest as the Test API is wider than system but
Paul Duffin2cb06b72021-06-21 14:08:08 +010089 // is neither wider or narrower than the module-lib or core platform APIs. However, this works
90 // well enough at the moment.
Paul Duffin05bbff92021-06-18 18:14:25 +010091 // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
92 hiddenAPIScopes = []*HiddenAPIScope{
93 PublicHiddenAPIScope,
94 SystemHiddenAPIScope,
95 TestHiddenAPIScope,
Paul Duffin2cb06b72021-06-21 14:08:08 +010096 ModuleLibHiddenAPIScope,
Paul Duffin05bbff92021-06-18 18:14:25 +010097 CorePlatformHiddenAPIScope,
98 }
99
100 // The HiddenAPIScope instances that are supported by a java_sdk_library.
101 //
102 // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
103 // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
104 hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{
105 PublicHiddenAPIScope,
106 SystemHiddenAPIScope,
107 TestHiddenAPIScope,
Paul Duffin2cb06b72021-06-21 14:08:08 +0100108 ModuleLibHiddenAPIScope,
Paul Duffin05bbff92021-06-18 18:14:25 +0100109 }
110
111 // The HiddenAPIScope instances that are supported by the `hiddenapi list`.
112 hiddenAPIFlagScopes = []*HiddenAPIScope{
113 PublicHiddenAPIScope,
114 SystemHiddenAPIScope,
115 TestHiddenAPIScope,
116 CorePlatformHiddenAPIScope,
117 }
118)
119
Paul Duffin74431d52021-04-21 14:10:42 +0100120type hiddenAPIStubsDependencyTag struct {
121 blueprint.BaseDependencyTag
Paul Duffin05bbff92021-06-18 18:14:25 +0100122
123 // The api scope for which this dependency was added.
124 apiScope *HiddenAPIScope
Paul Duffin74431d52021-04-21 14:10:42 +0100125}
126
127func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
128}
129
130func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool {
131 return false
132}
133
Paul Duffin976b0e52021-04-27 23:20:26 +0100134func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
135 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
136 // property, otherwise treat if it was specified in the java_header_libs property.
137 if javaSdkLibrarySdkMemberType.IsInstance(child) {
138 return javaSdkLibrarySdkMemberType
139 }
140
141 return javaHeaderLibsSdkMemberType
142}
143
144func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
145 // Export the module added via this dependency tag from the sdk.
146 return true
147}
148
Paul Duffin74431d52021-04-21 14:10:42 +0100149// Avoid having to make stubs content explicitly visible to dependent modules.
150//
151// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
152// with proper dependencies.
153// TODO(b/177892522): Remove this and add needed visibility.
154func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
155}
156
157var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
158var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
159var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
Paul Duffin976b0e52021-04-27 23:20:26 +0100160var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
Paul Duffin74431d52021-04-21 14:10:42 +0100161
Paul Duffin74431d52021-04-21 14:10:42 +0100162// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
163// needed to produce the hidden API monolithic stub flags file.
Paul Duffin05bbff92021-06-18 18:14:25 +0100164func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string {
Paul Duffin74431d52021-04-21 14:10:42 +0100165 var publicStubModules []string
166 var systemStubModules []string
167 var testStubModules []string
168 var corePlatformStubModules []string
169
170 if config.AlwaysUsePrebuiltSdks() {
171 // Build configuration mandates using prebuilt stub modules
172 publicStubModules = append(publicStubModules, "sdk_public_current_android")
173 systemStubModules = append(systemStubModules, "sdk_system_current_android")
174 testStubModules = append(testStubModules, "sdk_test_current_android")
175 } else {
176 // Use stub modules built from source
177 publicStubModules = append(publicStubModules, "android_stubs_current")
178 systemStubModules = append(systemStubModules, "android_system_stubs_current")
179 testStubModules = append(testStubModules, "android_test_stubs_current")
180 }
181 // We do not have prebuilts of the core platform api yet
182 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
183
184 // Allow products to define their own stubs for custom product jars that apps can use.
185 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
186 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
187 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
188 if config.IsEnvTrue("EMMA_INSTRUMENT") {
Paul Duffin098c8782021-05-14 10:45:25 +0100189 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
190 // allows everyone access but it is needed to ensure consistent flags between the
191 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
Paul Duffin74431d52021-04-21 14:10:42 +0100192 publicStubModules = append(publicStubModules, "jacoco-stubs")
Paul Duffin098c8782021-05-14 10:45:25 +0100193 systemStubModules = append(systemStubModules, "jacoco-stubs")
194 testStubModules = append(testStubModules, "jacoco-stubs")
Paul Duffin74431d52021-04-21 14:10:42 +0100195 }
196
Paul Duffin05bbff92021-06-18 18:14:25 +0100197 m := map[*HiddenAPIScope][]string{}
198 m[PublicHiddenAPIScope] = publicStubModules
199 m[SystemHiddenAPIScope] = systemStubModules
200 m[TestHiddenAPIScope] = testStubModules
201 m[CorePlatformHiddenAPIScope] = corePlatformStubModules
Paul Duffin74431d52021-04-21 14:10:42 +0100202 return m
203}
204
205// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
Paul Duffin05bbff92021-06-18 18:14:25 +0100206// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
207// tag to identify the source of the dependency.
208func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) {
Paul Duffin74431d52021-04-21 14:10:42 +0100209 module := ctx.Module()
Paul Duffin05bbff92021-06-18 18:14:25 +0100210 for _, apiScope := range hiddenAPIScopes {
211 modules := apiScopeToStubLibModules[apiScope]
212 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...)
Paul Duffin74431d52021-04-21 14:10:42 +0100213 }
214}
215
Paul Duffin74431d52021-04-21 14:10:42 +0100216// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
217// available, or reports an error.
Paul Duffin10931582021-04-25 10:13:54 +0100218func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
219 var dexJar android.Path
220 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
221 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
222 } else if j, ok := module.(UsesLibraryDependency); ok {
223 dexJar = j.DexJarBuildPath()
Paul Duffin74431d52021-04-21 14:10:42 +0100224 } else {
225 ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module))
Paul Duffin10931582021-04-25 10:13:54 +0100226 return nil
Paul Duffin74431d52021-04-21 14:10:42 +0100227 }
Paul Duffin10931582021-04-25 10:13:54 +0100228
229 if dexJar == nil {
230 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
231 }
232 return dexJar
Paul Duffin74431d52021-04-21 14:10:42 +0100233}
234
Paul Duffin31a68562021-06-23 23:20:43 +0100235// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
Paul Duffin74431d52021-04-21 14:10:42 +0100236//
237// The rule is initialized but not built so that the caller can modify it and select an appropriate
238// name.
Paul Duffinaf193422021-06-23 23:29:09 +0100239func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) {
Paul Duffin74431d52021-04-21 14:10:42 +0100240 // Singleton rule which applies hiddenapi on all boot class path dex files.
241 rule := android.NewRuleBuilder(pctx, ctx)
242
243 tempPath := tempPathForRestat(ctx, outputPath)
244
Paul Duffin67c1e572021-05-17 07:38:47 +0100245 // Find the widest API stubs provided by the fragments on which this depends, if any.
246 var dependencyStubDexJars android.Paths
Paul Duffin05bbff92021-06-18 18:14:25 +0100247 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
248 apiScope := hiddenAPIScopes[i]
249 stubsForAPIScope := input.DependencyStubDexJarsByScope[apiScope]
250 if len(stubsForAPIScope) != 0 {
251 dependencyStubDexJars = stubsForAPIScope
Paul Duffin67c1e572021-05-17 07:38:47 +0100252 break
253 }
254 }
255
Paul Duffin74431d52021-04-21 14:10:42 +0100256 command := rule.Command().
257 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
258 Text("list").
Paul Duffin67c1e572021-05-17 07:38:47 +0100259 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100260 FlagForEachInput("--boot-dex=", bootDexJars)
261
Paul Duffin05bbff92021-06-18 18:14:25 +0100262 // Iterate over the api scopes in a fixed order.
263 for _, apiScope := range hiddenAPIFlagScopes {
264 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
265 // They will be needed to resolve dependencies from this fragment's stubs to classes in the
266 // other fragment's APIs.
267 var paths android.Paths
268 paths = append(paths, input.DependencyStubDexJarsByScope[apiScope]...)
269 paths = append(paths, input.StubDexJarsByScope[apiScope]...)
Paul Duffin74431d52021-04-21 14:10:42 +0100270 if len(paths) > 0 {
Paul Duffin05bbff92021-06-18 18:14:25 +0100271 option := apiScope.hiddenAPIListOption
272 command.FlagWithInputList(option+"=", paths, ":")
Paul Duffin74431d52021-04-21 14:10:42 +0100273 }
274 }
275
276 // Add the output path.
277 command.FlagWithOutput("--out-api-flags=", tempPath)
278
Paul Duffinaf193422021-06-23 23:29:09 +0100279 // If there are stub flag files that have been generated by fragments on which this depends then
280 // use them to validate the stub flag file generated by the rules created by this method.
281 if len(moduleStubFlagsPaths) > 0 {
282 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths)
283
284 // Add the file that indicates that the file generated by this is valid.
285 //
286 // This will cause the validation rule above to be run any time that the output of this rule
287 // changes but the validation will run in parallel with other rules that depend on this file.
288 command.Validation(validFile)
289 }
290
Paul Duffin74431d52021-04-21 14:10:42 +0100291 commitChangeForRestat(rule, tempPath, outputPath)
Paul Duffin31a68562021-06-23 23:20:43 +0100292
293 rule.Build(name, desc)
Paul Duffin74431d52021-04-21 14:10:42 +0100294}
295
Paul Duffin46169772021-04-14 15:01:56 +0100296// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
297// information obtained from annotations within the source code in order to create the complete set
298// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100299//
300// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
301// of each property reference a plain text file that contains a java signature per line. The flags
302// for each of those signatures will be updated in a property specific way.
303//
304// The Unsupported_packages property contains a list of paths, each of which is a plain text file
305// with one Java package per line. All members of all classes within that package (but not nested
306// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100307type HiddenAPIFlagFileProperties struct {
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100308 // Marks each signature in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100309 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100310
311 // Marks each signature in the referenced files as being unsupported because it has been removed.
312 // Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100313 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100314
315 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
316 // and low priority.
Paul Duffin702210b2021-04-08 20:12:41 +0100317 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100318
319 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
Paul Duffin702210b2021-04-08 20:12:41 +0100320 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100321
322 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
Paul Duffin702210b2021-04-08 20:12:41 +0100323 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100324
325 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
326 // and low priority. Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100327 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100328
329 // Marks each signature in the referenced files as being blocked.
Paul Duffin702210b2021-04-08 20:12:41 +0100330 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100331
332 // Marks each signature in every package in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100333 Unsupported_packages []string `android:"path"`
334}
335
Paul Duffine3dc6602021-04-14 09:50:43 +0100336type hiddenAPIFlagFileCategory struct {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100337 // PropertyName is the name of the property for this category.
338 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100339
Paul Duffincc17bfe2021-04-19 13:21:20 +0100340 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100341 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100342 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100343
344 // commandMutator adds the appropriate command line options for this category to the supplied
345 // command
346 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
347}
348
Paul Duffin54c1f082021-05-18 16:32:50 +0100349// The flag file category for removed members of the API.
350//
Paul Duffinc45a86a2021-06-09 14:39:28 +0100351// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin54c1f082021-05-18 16:32:50 +0100352// list of removed API members that are generated automatically from the removed.txt files provided
353// by API stubs.
354var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
355 // See HiddenAPIFlagFileProperties.Removed
Paul Duffinc45a86a2021-06-09 14:39:28 +0100356 PropertyName: "removed",
Paul Duffin54c1f082021-05-18 16:32:50 +0100357 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
358 return properties.Removed
359 },
360 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
361 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
362 },
363}
364
Paul Duffinc45a86a2021-06-09 14:39:28 +0100365var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
Paul Duffin46169772021-04-14 15:01:56 +0100366 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100367 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100368 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100369 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100370 return properties.Unsupported
371 },
372 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
373 command.FlagWithInput("--unsupported ", path)
374 },
375 },
Paul Duffin54c1f082021-05-18 16:32:50 +0100376 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100377 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100378 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100379 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100380 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100381 return properties.Max_target_r_low_priority
382 },
383 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
384 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
385 },
386 },
Paul Duffin46169772021-04-14 15:01:56 +0100387 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100388 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100389 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100390 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100391 return properties.Max_target_q
392 },
393 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
394 command.FlagWithInput("--max-target-q ", path)
395 },
396 },
Paul Duffin46169772021-04-14 15:01:56 +0100397 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100398 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100399 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100400 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100401 return properties.Max_target_p
402 },
403 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
404 command.FlagWithInput("--max-target-p ", path)
405 },
406 },
Paul Duffin46169772021-04-14 15:01:56 +0100407 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100408 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100409 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100410 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100411 return properties.Max_target_o_low_priority
412 },
413 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
414 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
415 },
416 },
Paul Duffin46169772021-04-14 15:01:56 +0100417 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100418 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100419 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100420 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100421 return properties.Blocked
422 },
423 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
424 command.FlagWithInput("--blocked ", path)
425 },
426 },
Paul Duffin46169772021-04-14 15:01:56 +0100427 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100428 {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100429 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100430 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100431 return properties.Unsupported_packages
432 },
433 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
434 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
435 },
436 },
Paul Duffin702210b2021-04-08 20:12:41 +0100437}
438
Paul Duffin9e3b9062021-05-21 16:58:23 +0100439// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
440type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
441
442// append appends the supplied flags files to the corresponding category in this map.
443func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100444 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin9e3b9062021-05-21 16:58:23 +0100445 s[category] = append(s[category], other[category]...)
446 }
447}
448
449// dedup removes duplicates in the flag files, while maintaining the order in which they were
450// appended.
451func (s FlagFilesByCategory) dedup() {
452 for category, paths := range s {
453 s[category] = android.FirstUniquePaths(paths)
454 }
455}
456
Paul Duffin71955b42021-05-21 22:18:56 +0100457// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100458//
Paul Duffin71955b42021-05-21 22:18:56 +0100459// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
460// processing.
461type HiddenAPIInfo struct {
Paul Duffin9e3b9062021-05-21 16:58:23 +0100462 // FlagFilesByCategory maps from the flag file category to the paths containing information for
463 // that category.
464 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100465
Paul Duffin05bbff92021-06-18 18:14:25 +0100466 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes.
467 TransitiveStubDexJarsByScope StubDexJarsByScope
Paul Duffin6a58cc92021-05-21 22:46:59 +0100468
Paul Duffincad63842021-05-21 16:15:31 +0100469 // The output from the hidden API processing needs to be made available to other modules.
470 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100471}
Paul Duffin702210b2021-04-08 20:12:41 +0100472
Paul Duffin67c1e572021-05-17 07:38:47 +0100473func newHiddenAPIInfo() *HiddenAPIInfo {
474 info := HiddenAPIInfo{
Paul Duffin05bbff92021-06-18 18:14:25 +0100475 FlagFilesByCategory: FlagFilesByCategory{},
476 TransitiveStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffin67c1e572021-05-17 07:38:47 +0100477 }
478 return &info
479}
480
481func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
482 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
483 // this will introduce duplicates so they will be resolved after processing all the fragments.
484 for _, fragment := range fragments {
485 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
486 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
Paul Duffin05bbff92021-06-18 18:14:25 +0100487 i.TransitiveStubDexJarsByScope.append(info.TransitiveStubDexJarsByScope)
Paul Duffin67c1e572021-05-17 07:38:47 +0100488 }
489 }
490
491 // Dedup and sort paths.
Paul Duffin05bbff92021-06-18 18:14:25 +0100492 i.TransitiveStubDexJarsByScope.dedupAndSort()
Paul Duffin67c1e572021-05-17 07:38:47 +0100493}
494
Paul Duffin71955b42021-05-21 22:18:56 +0100495var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100496
Paul Duffin05bbff92021-06-18 18:14:25 +0100497// StubDexJarsByScope maps a *HiddenAPIScope to the paths to stub dex jars appropriate for that
498// scope. See hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
499type StubDexJarsByScope map[*HiddenAPIScope]android.Paths
Paul Duffin5aadef82021-05-21 22:18:49 +0100500
Paul Duffin05bbff92021-06-18 18:14:25 +0100501// append appends the API scope specific stub dex jar args to the corresponding scope in this
Paul Duffin5aadef82021-05-21 22:18:49 +0100502// map.
Paul Duffin05bbff92021-06-18 18:14:25 +0100503func (s StubDexJarsByScope) append(other StubDexJarsByScope) {
504 for _, scope := range hiddenAPIScopes {
505 s[scope] = append(s[scope], other[scope]...)
Paul Duffin5aadef82021-05-21 22:18:49 +0100506 }
507}
508
509// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
510// deterministic order.
Paul Duffin05bbff92021-06-18 18:14:25 +0100511func (s StubDexJarsByScope) dedupAndSort() {
512 for apiScope, paths := range s {
513 s[apiScope] = android.SortedUniquePaths(paths)
Paul Duffin5aadef82021-05-21 22:18:49 +0100514 }
515}
516
517// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
518// needed for hidden API flag generation.
519type HiddenAPIFlagInput struct {
520 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
521 // from the stub dex files.
522 FlagFilesByCategory FlagFilesByCategory
523
Paul Duffin05bbff92021-06-18 18:14:25 +0100524 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
Paul Duffin5aadef82021-05-21 22:18:49 +0100525 // the initial flags for each dex member.
Paul Duffin05bbff92021-06-18 18:14:25 +0100526 StubDexJarsByScope StubDexJarsByScope
Paul Duffin67c1e572021-05-17 07:38:47 +0100527
Paul Duffin05bbff92021-06-18 18:14:25 +0100528 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
529 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
Paul Duffin67c1e572021-05-17 07:38:47 +0100530 // fragment on which this depends.
Paul Duffin05bbff92021-06-18 18:14:25 +0100531 DependencyStubDexJarsByScope StubDexJarsByScope
Paul Duffin54c1f082021-05-18 16:32:50 +0100532
533 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
534 // specified in the bootclasspath_fragment's stub_libs and contents properties.
535 RemovedTxtFiles android.Paths
Paul Duffin5aadef82021-05-21 22:18:49 +0100536}
537
538// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
539func newHiddenAPIFlagInput() HiddenAPIFlagInput {
540 input := HiddenAPIFlagInput{
Paul Duffin05bbff92021-06-18 18:14:25 +0100541 FlagFilesByCategory: FlagFilesByCategory{},
542 StubDexJarsByScope: StubDexJarsByScope{},
543 DependencyStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffin5aadef82021-05-21 22:18:49 +0100544 }
545
546 return input
547}
548
Paul Duffin699a0042021-05-23 16:55:37 +0100549// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
550//
551// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
552// appropriate information needed for hidden API processing breaking the build.
553// TODO(b/179354495): Remove this workaround.
554func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
555 // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
556 // required as the whole point of adding something to the bootclasspath fragment is to add it to
557 // the bootclasspath in order to be used by something else in the system. Without any stubs it
558 // cannot do that.
Paul Duffin05bbff92021-06-18 18:14:25 +0100559 if len(i.StubDexJarsByScope) == 0 {
Paul Duffin699a0042021-05-23 16:55:37 +0100560 return false
561 }
562
563 // Hidden API processing is always enabled in tests.
564 if ctx.Config().TestProductVariables != nil {
565 return true
566 }
567
568 // A module that has fragments should have access to the information it needs in order to perform
569 // hidden API processing.
570 if len(properties.Fragments) != 0 {
571 return true
572 }
573
574 // The art bootclasspath fragment does not depend on any other fragments but already supports
575 // hidden API processing.
576 imageName := proptools.String(properties.Image_name)
577 if imageName == "art" {
578 return true
579 }
580
581 // Disable it for everything else.
582 return false
583}
584
Paul Duffin5aadef82021-05-21 22:18:49 +0100585// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
586// dependencies added in hiddenAPIAddStubLibDependencies.
587//
588// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
589func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
Paul Duffin05bbff92021-06-18 18:14:25 +0100590 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
591 sdkKind := apiScope.sdkKind
592 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
Paul Duffin5aadef82021-05-21 22:18:49 +0100593 if dexJar != nil {
Paul Duffin05bbff92021-06-18 18:14:25 +0100594 i.StubDexJarsByScope[apiScope] = append(i.StubDexJarsByScope[apiScope], dexJar)
Paul Duffin5aadef82021-05-21 22:18:49 +0100595 }
Paul Duffin54c1f082021-05-18 16:32:50 +0100596
597 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
Paul Duffin05bbff92021-06-18 18:14:25 +0100598 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
Paul Duffin54c1f082021-05-18 16:32:50 +0100599 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
600 }
Paul Duffin5aadef82021-05-21 22:18:49 +0100601 }
602
603 // If the contents includes any java_sdk_library modules then add them to the stubs.
604 for _, module := range contents {
605 if _, ok := module.(SdkLibraryDependency); ok {
Paul Duffin05bbff92021-06-18 18:14:25 +0100606 // Add information for every possible API scope needed by hidden API.
607 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
608 addFromModule(ctx, module, apiScope)
Paul Duffin5aadef82021-05-21 22:18:49 +0100609 }
610 }
611 }
612
Paul Duffin2a999332021-06-07 21:36:01 +0100613 ctx.VisitDirectDeps(func(module android.Module) {
Paul Duffin5aadef82021-05-21 22:18:49 +0100614 tag := ctx.OtherModuleDependencyTag(module)
615 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
Paul Duffin05bbff92021-06-18 18:14:25 +0100616 apiScope := hiddenAPIStubsTag.apiScope
617 addFromModule(ctx, module, apiScope)
Paul Duffin5aadef82021-05-21 22:18:49 +0100618 }
619 })
620
621 // Normalize the paths, i.e. remove duplicates and sort.
Paul Duffin05bbff92021-06-18 18:14:25 +0100622 i.StubDexJarsByScope.dedupAndSort()
623 i.DependencyStubDexJarsByScope.dedupAndSort()
Paul Duffin54c1f082021-05-18 16:32:50 +0100624 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin5aadef82021-05-21 22:18:49 +0100625}
626
627// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
628// supplied properties and stores them in this struct.
629func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
Paul Duffinc45a86a2021-06-09 14:39:28 +0100630 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin5aadef82021-05-21 22:18:49 +0100631 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
632 i.FlagFilesByCategory[category] = paths
633 }
634}
635
Paul Duffin05bbff92021-06-18 18:14:25 +0100636func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByScope {
637 transitive := i.DependencyStubDexJarsByScope
638 transitive.append(i.StubDexJarsByScope)
Paul Duffin67c1e572021-05-17 07:38:47 +0100639 return transitive
640}
641
Paul Duffincad63842021-05-21 16:15:31 +0100642// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
643// bootclasspath_fragment module.
644type HiddenAPIFlagOutput struct {
645 // The path to the generated stub-flags.csv file.
646 StubFlagsPath android.Path
647
648 // The path to the generated annotation-flags.csv file.
649 AnnotationFlagsPath android.Path
650
651 // The path to the generated metadata.csv file.
652 MetadataPath android.Path
653
654 // The path to the generated index.csv file.
655 IndexPath android.Path
656
657 // The path to the generated all-flags.csv file.
658 AllFlagsPath android.Path
659}
660
Paul Duffin3e2db5c2021-06-02 17:24:22 +0100661// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
662// path.
663type bootDexJarByModule map[string]android.Path
664
665// addPath adds the path for a module to the map.
666func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
667 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
668}
669
Paul Duffinc75bbce2021-06-07 13:28:19 +0100670// bootDexJars returns the boot dex jar paths sorted by their keys.
671func (b bootDexJarByModule) bootDexJars() android.Paths {
672 paths := android.Paths{}
673 for _, k := range android.SortedStringKeys(b) {
674 paths = append(paths, b[k])
675 }
676 return paths
677}
678
Paul Duffin4fd7dc72021-06-17 19:33:24 +0100679// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
680// libraries if present.
681func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
682 paths := android.Paths{}
683 for _, k := range android.SortedStringKeys(b) {
684 if k == "jacocoagent" {
685 continue
686 }
687 paths = append(paths, b[k])
688 }
689 return paths
690}
691
Paul Duffinc75bbce2021-06-07 13:28:19 +0100692// HiddenAPIOutput encapsulates the output from the hidden API processing.
693type HiddenAPIOutput struct {
694 HiddenAPIFlagOutput
695
696 // The map from base module name to the path to the encoded boot dex file.
697 EncodedBootDexFilesByModule bootDexJarByModule
698}
699
Paul Duffindfa10832021-05-13 17:31:51 +0100700// pathForValidation creates a path of the same type as the supplied type but with a name of
701// <path>.valid.
702//
703// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
704// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
705func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
706 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
707 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
708}
709
Paul Duffin2fef1362021-04-15 13:32:00 +0100710// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
711// the flags from all the modules, the stub flags, augmented with some additional configuration
712// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100713//
714// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
715// an entry for every single member in the dex implementation jars of the individual modules. Every
716// signature in any of the other files MUST be included in this file.
717//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100718// annotationFlags is the path to the annotation flags file generated from annotation information
719// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100720//
Paul Duffin71955b42021-05-21 22:18:56 +0100721// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100722// the annotationFlags.
Paul Duffin54c1f082021-05-18 16:32:50 +0100723func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
Paul Duffin2a999332021-06-07 21:36:01 +0100724 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
Paul Duffin54c1f082021-05-18 16:32:50 +0100725 flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100726
Paul Duffindfa10832021-05-13 17:31:51 +0100727 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100728 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100729 rule := android.NewRuleBuilder(pctx, ctx)
730 command := rule.Command().
731 BuiltTool("generate_hiddenapi_lists").
732 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffin2a999332021-06-07 21:36:01 +0100733 Inputs(annotationFlagPaths).
Paul Duffin702210b2021-04-08 20:12:41 +0100734 FlagWithOutput("--output ", tempPath)
735
Paul Duffine3dc6602021-04-14 09:50:43 +0100736 // Add the options for the different categories of flag files.
Paul Duffinc45a86a2021-06-09 14:39:28 +0100737 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin9e3b9062021-05-21 16:58:23 +0100738 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100739 for _, path := range paths {
740 category.commandMutator(command, path)
741 }
Paul Duffin702210b2021-04-08 20:12:41 +0100742 }
743
Paul Duffin54c1f082021-05-18 16:32:50 +0100744 // If available then pass the automatically generated file containing dex signatures of removed
745 // API members to the rule so they can be marked as removed.
746 if generatedRemovedDexSignatures.Valid() {
747 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
748 }
749
Paul Duffin702210b2021-04-08 20:12:41 +0100750 commitChangeForRestat(rule, tempPath, outputPath)
751
Paul Duffinaf193422021-06-23 23:29:09 +0100752 // If there are flag files that have been generated by fragments on which this depends then use
753 // them to validate the flag file generated by the rules created by this method.
754 if len(allFlagsPaths) > 0 {
755 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths)
756
Paul Duffindfa10832021-05-13 17:31:51 +0100757 // Add the file that indicates that the file generated by this is valid.
758 //
759 // This will cause the validation rule above to be run any time that the output of this rule
760 // changes but the validation will run in parallel with other rules that depend on this file.
761 command.Validation(validFile)
762 }
763
Paul Duffin2fef1362021-04-15 13:32:00 +0100764 rule.Build(name, desc)
765}
766
Paul Duffinaf193422021-06-23 23:29:09 +0100767// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
768// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
769func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath {
770 // The file which is used to record that the flags file is valid.
771 validFile := pathForValidation(ctx, monolithicFilePath)
772
773 // Create a rule to validate the output from the following rule.
774 rule := android.NewRuleBuilder(pctx, ctx)
775 rule.Command().
776 BuiltTool("verify_overlaps").
777 Input(monolithicFilePath).
778 Inputs(modularFilePaths).
779 // If validation passes then update the file that records that.
780 Text("&& touch").Output(validFile)
781 rule.Build(name+"Validation", desc+" validation")
782
783 return validFile
784}
785
Paul Duffinc75bbce2021-06-07 13:28:19 +0100786// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
787// bootclasspath and then encode the flags into the boot dex files.
Paul Duffin2fef1362021-04-15 13:32:00 +0100788//
789// It takes:
790// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
791// * The list of modules that are the contents of the fragment.
792// * The additional manually curated flag files to use.
793//
794// It generates:
795// * stub-flags.csv
796// * annotation-flags.csv
797// * metadata.csv
798// * index.csv
799// * all-flags.csv
Paul Duffinc75bbce2021-06-07 13:28:19 +0100800// * encoded boot dex files
801func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +0100802 hiddenApiSubDir := "modular-hiddenapi"
803
Paul Duffinc75bbce2021-06-07 13:28:19 +0100804 // Gather information about the boot dex files for the boot libraries provided by this fragment.
805 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
Paul Duffin5aadef82021-05-21 22:18:49 +0100806
807 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +0100808 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffinaf193422021-06-23 23:29:09 +0100809 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
Paul Duffin2fef1362021-04-15 13:32:00 +0100810
Paul Duffin537ea3d2021-05-14 10:38:00 +0100811 // Extract the classes jars from the contents.
Paul Duffin98ea0d42021-06-10 10:18:22 +0100812 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100813
Paul Duffin2fef1362021-04-15 13:32:00 +0100814 // Generate the set of flags from the annotations in the source code.
815 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100816 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100817
818 // Generate the metadata from the annotations in the source code.
819 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100820 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100821
Paul Duffin537ea3d2021-05-14 10:38:00 +0100822 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +0100823 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100824 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100825
Paul Duffin71955b42021-05-21 22:18:56 +0100826 // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files
Paul Duffin2fef1362021-04-15 13:32:00 +0100827 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
828 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin54c1f082021-05-18 16:32:50 +0100829 // signatures, see the combined-removed-dex module. This does that automatically by using the
830 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
831 // stub_libs and contents properties of a bootclasspath_fragment.
832 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +0100833
834 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
835 // files.
Paul Duffinc75bbce2021-06-07 13:28:19 +0100836 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
Paul Duffin2a999332021-06-07 21:36:01 +0100837 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
Paul Duffinc75bbce2021-06-07 13:28:19 +0100838
839 // Encode the flags into the boot dex files.
840 encodedBootDexJarsByModule := map[string]android.Path{}
841 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
842 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
843 bootDexInfo := bootDexInfoByModule[name]
844 unencodedDex := bootDexInfo.path
845 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
846 encodedBootDexJarsByModule[name] = encodedDex
847 }
Paul Duffin2fef1362021-04-15 13:32:00 +0100848
849 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffinc75bbce2021-06-07 13:28:19 +0100850 output := HiddenAPIOutput{
851 HiddenAPIFlagOutput: HiddenAPIFlagOutput{
852 StubFlagsPath: stubFlagsCSV,
853 AnnotationFlagsPath: annotationFlagsCSV,
854 MetadataPath: metadataCSV,
855 IndexPath: indexCSV,
856 AllFlagsPath: allFlagsCSV,
857 },
858 EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
Paul Duffincad63842021-05-21 16:15:31 +0100859 }
860 return &output
Paul Duffin702210b2021-04-08 20:12:41 +0100861}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100862
Paul Duffin54c1f082021-05-18 16:32:50 +0100863func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
864 if len(removedTxtFiles) == 0 {
865 return android.OptionalPath{}
866 }
867
868 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
869
870 rule := android.NewRuleBuilder(pctx, ctx)
871 rule.Command().
872 BuiltTool("metalava").
873 Flag("--no-banner").
874 Inputs(removedTxtFiles).
875 FlagWithOutput("--dex-api ", output)
876 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
877 return android.OptionalPathForPath(output)
878}
879
Paul Duffin98ea0d42021-06-10 10:18:22 +0100880// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffinc75bbce2021-06-07 13:28:19 +0100881func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
882 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100883 for _, module := range contents {
Paul Duffin98ea0d42021-06-10 10:18:22 +0100884 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
885 if hiddenAPIModule == nil {
886 continue
887 }
Paul Duffinc75bbce2021-06-07 13:28:19 +0100888 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
889 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100890 }
891 return bootDexJars
892}
893
Paul Duffin98ea0d42021-06-10 10:18:22 +0100894func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
895 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
896 return hiddenAPIModule
897 } else if _, ok := module.(*DexImport); ok {
898 // Ignore this for the purposes of hidden API processing
899 } else {
900 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
901 }
902
903 return nil
904}
905
Paul Duffinc75bbce2021-06-07 13:28:19 +0100906// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
907type bootDexInfo struct {
908 // The path to the dex jar that has not had hidden API flags encoded into it.
909 path android.Path
910
911 // Indicates whether the dex jar needs uncompressing before encoding.
912 uncompressDex bool
913}
914
915// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
916// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
917type bootDexInfoByModule map[string]bootDexInfo
918
919// bootDexJars returns the boot dex jar paths sorted by their keys.
920func (b bootDexInfoByModule) bootDexJars() android.Paths {
921 paths := android.Paths{}
922 for _, m := range android.SortedStringKeys(b) {
923 paths = append(paths, b[m].path)
924 }
925 return paths
926}
927
928// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
929// each of the supplied modules which must implement hiddenAPIModule.
930func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
931 bootDexJarsByModule := bootDexInfoByModule{}
932 for _, module := range contents {
933 hiddenAPIModule := module.(hiddenAPIModule)
934 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
935 bootDexJarsByModule[module.Name()] = bootDexInfo{
936 path: bootDexJar,
937 uncompressDex: *hiddenAPIModule.uncompressDex(),
938 }
939 }
940
941 return bootDexJarsByModule
942}
943
944// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
945//
946// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
947// create a fake path and either report an error immediately or defer reporting of the error until
948// the path is actually used.
949func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
950 bootDexJar := module.bootDexJar()
951 if bootDexJar == nil {
952 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
953 bootDexJar = fake
954
955 handleMissingDexBootFile(ctx, module, fake)
956 }
957 return bootDexJar
958}
959
Paul Duffin98ea0d42021-06-10 10:18:22 +0100960// extractClassesJarsFromModules extracts the class jars from the supplied modules.
961func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +0100962 classesJars := android.Paths{}
963 for _, module := range contents {
Paul Duffin98ea0d42021-06-10 10:18:22 +0100964 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100965 }
966 return classesJars
967}
Paul Duffin3e2db5c2021-06-02 17:24:22 +0100968
Paul Duffin98ea0d42021-06-10 10:18:22 +0100969// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
970func retrieveClassesJarsFromModule(module android.Module) android.Paths {
971 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
972 return hiddenAPIModule.classesJars()
973 }
974
975 return nil
976}
977
Paul Duffin3e2db5c2021-06-02 17:24:22 +0100978// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
979// Soong but should instead only be reported in ninja if the file is actually built.
980func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
981 // TODO(b/179354495): Remove this workaround when it is unnecessary.
982 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
983 // create a fake one that will cause a build error only if it is used.
984 if ctx.Config().AlwaysUsePrebuiltSdks() {
985 return true
986 }
987
Paul Duffinc75bbce2021-06-07 13:28:19 +0100988 // Any missing dependency should be allowed.
989 if ctx.Config().AllowMissingDependencies() {
990 return true
991 }
992
Paul Duffin3e2db5c2021-06-02 17:24:22 +0100993 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
994 //
995 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
996 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
997 // but unfortunately, due to b/187910671 it does.
998 //
999 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
1000 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
1001 // has an APEX variant not a platform variant.
1002 //
1003 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
1004 // provide a boot dex jar:
1005 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
1006 // does not have an APEX variant and only has a platform variant and neither do its content
1007 // modules.
1008 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
1009 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
1010 // of an apex they cannot provide a boot dex jar.
1011 //
1012 // The first case causes problems when the affected prebuilt modules are preferred but that is an
1013 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
1014 // complete. The second case is used for building targets that do not use boot dex jars and so
1015 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
1016 // That is handled above.
1017 //
1018 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
1019 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
1020 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
1021 // that if the library can be part of an APEX then it is the APEX variant that is used.
1022 //
1023 // This check handles the slightly different requirements of the bootclasspath_fragment and
1024 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
1025 // a prebuilt modules that has other variants which are part of an APEX.
1026 //
1027 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
1028 if android.IsModulePrebuilt(module) {
1029 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
1030 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
1031 if apexInfo.IsForPlatform() {
1032 return true
1033 }
1034 }
1035 }
1036
1037 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
1038 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
1039 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
1040 // failures missing boot dex jars need to be deferred.
1041 if android.IsModuleInVersionedSdk(ctx.Module()) {
1042 return true
1043 }
1044
1045 return false
1046}
1047
1048// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
1049// file depending on the value returned from deferReportingMissingBootDexJar.
1050func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
1051 if deferReportingMissingBootDexJar(ctx, module) {
1052 // Create an error rule that pretends to create the output file but will actually fail if it
1053 // is run.
1054 ctx.Build(pctx, android.BuildParams{
1055 Rule: android.ErrorRule,
1056 Output: fake,
1057 Args: map[string]string{
1058 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
1059 },
1060 })
1061 } else {
1062 ctx.ModuleErrorf("module %s does not provide a dex jar", module)
1063 }
1064}
1065
1066// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
1067// DexJarBuildPath() method.
1068//
1069// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
1070// However, under certain conditions, e.g. errors, or special build configurations it will return
1071// a path to a fake file.
1072func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
1073 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
1074 if bootDexJar == nil {
1075 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
1076 bootDexJar = fake
1077
1078 handleMissingDexBootFile(ctx, module, fake)
1079 }
1080 return bootDexJar
1081}
1082
1083// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
1084func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1085 encodedDexJarsByModuleName := bootDexJarByModule{}
1086 for _, module := range contents {
1087 path := retrieveEncodedBootDexJarFromModule(ctx, module)
1088 encodedDexJarsByModuleName.addPath(module, path)
1089 }
1090 return encodedDexJarsByModuleName
1091}