blob: b322c6fd2d321c1d6e766799d0f1c7a6dd387ec8 [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 Duffin7487a7a2021-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 Duffin62370922021-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 Duffin31fad802021-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
Paul Duffin5cca7c42021-05-26 10:16:01 +010040
41 // The name sof the source stub library modules that contain the API provided by the platform,
42 // i.e. by modules that are not in an APEX.
43 nonUpdatableSourceModule string
44
45 // The names of the prebuilt stub library modules that contain the API provided by the platform,
46 // i.e. by modules that are not in an APEX.
47 nonUpdatablePrebuiltModule string
Paul Duffin31fad802021-06-18 18:14:25 +010048}
49
50// initHiddenAPIScope initializes the scope.
51func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
Paul Duffin5cca7c42021-05-26 10:16:01 +010052 sdkKind := apiScope.sdkKind
53 // The platform does not provide a core platform API.
54 if sdkKind != android.SdkCorePlatform {
55 kindAsString := sdkKind.String()
56 var insert string
57 if sdkKind == android.SdkPublic {
58 insert = ""
59 } else {
60 insert = "." + strings.ReplaceAll(kindAsString, "-", "_")
61 }
62
63 nonUpdatableModule := "android-non-updatable"
64
65 // Construct the name of the android-non-updatable source module for this scope.
66 apiScope.nonUpdatableSourceModule = fmt.Sprintf("%s.stubs%s", nonUpdatableModule, insert)
67
68 prebuiltModuleName := func(name string, kind string) string {
69 return fmt.Sprintf("sdk_%s_current_%s", kind, name)
70 }
71
72 // Construct the name of the android-non-updatable prebuilt module for this scope.
73 apiScope.nonUpdatablePrebuiltModule = prebuiltModuleName(nonUpdatableModule, kindAsString)
74 }
75
Paul Duffin31fad802021-06-18 18:14:25 +010076 return apiScope
77}
78
Paul Duffin5cca7c42021-05-26 10:16:01 +010079// android-non-updatable takes the name of a module and returns a possibly scope specific name of
80// the module.
81func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext, name string) string {
82 // The android-non-updatable is not a java_sdk_library but there are separate stub libraries for
83 // each scope.
84 // TODO(b/192067200): Remove special handling of android-non-updatable.
85 if name == "android-non-updatable" {
86 if ctx.Config().AlwaysUsePrebuiltSdks() {
87 return l.nonUpdatablePrebuiltModule
88 } else {
89 return l.nonUpdatableSourceModule
90 }
91 } else {
92 // Assume that the module is either a java_sdk_library (or equivalent) and so will provide
93 // separate stub jars for each scope or is a java_library (or equivalent) in which case it will
94 // have the same stub jar for each scope.
95 return name
96 }
97}
98
Paul Duffin31fad802021-06-18 18:14:25 +010099func (l *HiddenAPIScope) String() string {
100 return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
101}
102
103var (
104 PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
105 name: "public",
106 sdkKind: android.SdkPublic,
107 hiddenAPIListOption: "--public-stub-classpath",
108 })
109 SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
110 name: "system",
111 sdkKind: android.SdkSystem,
112 hiddenAPIListOption: "--system-stub-classpath",
113 })
114 TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
115 name: "test",
116 sdkKind: android.SdkTest,
117 hiddenAPIListOption: "--test-stub-classpath",
118 })
Paul Duffinb51db2e2021-06-21 14:08:08 +0100119 ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
120 name: "module-lib",
121 sdkKind: android.SdkModule,
122 })
Paul Duffin31fad802021-06-18 18:14:25 +0100123 CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
124 name: "core-platform",
125 sdkKind: android.SdkCorePlatform,
126 hiddenAPIListOption: "--core-platform-stub-classpath",
127 })
128
129 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
130 // API processing.
131 //
132 // These are roughly in order from narrowest API surface to widest. Widest means the API stubs
133 // with the biggest API surface, e.g. test is wider than system is wider than public.
134 //
Paul Duffinb51db2e2021-06-21 14:08:08 +0100135 // Core platform is considered wider than system/module-lib because those modules that provide
136 // core platform APIs either do not have any system/module-lib APIs at all, or if they do it is
137 // because the core platform API is being converted to system/module-lib APIs. In either case the
138 // system/module-lib APIs are subsets of the core platform API.
Paul Duffin31fad802021-06-18 18:14:25 +0100139 //
140 // This is not strictly in order from narrowest to widest as the Test API is wider than system but
Paul Duffinb51db2e2021-06-21 14:08:08 +0100141 // is neither wider or narrower than the module-lib or core platform APIs. However, this works
142 // well enough at the moment.
Paul Duffin31fad802021-06-18 18:14:25 +0100143 // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
144 hiddenAPIScopes = []*HiddenAPIScope{
145 PublicHiddenAPIScope,
146 SystemHiddenAPIScope,
147 TestHiddenAPIScope,
Paul Duffinb51db2e2021-06-21 14:08:08 +0100148 ModuleLibHiddenAPIScope,
Paul Duffin31fad802021-06-18 18:14:25 +0100149 CorePlatformHiddenAPIScope,
150 }
151
152 // The HiddenAPIScope instances that are supported by a java_sdk_library.
153 //
154 // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
155 // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
156 hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{
157 PublicHiddenAPIScope,
158 SystemHiddenAPIScope,
159 TestHiddenAPIScope,
Paul Duffinb51db2e2021-06-21 14:08:08 +0100160 ModuleLibHiddenAPIScope,
Paul Duffin31fad802021-06-18 18:14:25 +0100161 }
162
163 // The HiddenAPIScope instances that are supported by the `hiddenapi list`.
164 hiddenAPIFlagScopes = []*HiddenAPIScope{
165 PublicHiddenAPIScope,
166 SystemHiddenAPIScope,
167 TestHiddenAPIScope,
168 CorePlatformHiddenAPIScope,
169 }
170)
171
Paul Duffin74431d52021-04-21 14:10:42 +0100172type hiddenAPIStubsDependencyTag struct {
173 blueprint.BaseDependencyTag
Paul Duffin31fad802021-06-18 18:14:25 +0100174
175 // The api scope for which this dependency was added.
176 apiScope *HiddenAPIScope
Paul Duffin5cca7c42021-05-26 10:16:01 +0100177
178 // Indicates that the dependency is not for an API provided by the current bootclasspath fragment
179 // but is an additional API provided by a module that is not part of the current bootclasspath
180 // fragment.
181 fromAdditionalDependency bool
Paul Duffin74431d52021-04-21 14:10:42 +0100182}
183
184func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
185}
186
187func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool {
188 return false
189}
190
Paul Duffin976b0e52021-04-27 23:20:26 +0100191func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100192 // Do not add additional dependencies to the sdk.
193 if b.fromAdditionalDependency {
194 return nil
195 }
196
Paul Duffin976b0e52021-04-27 23:20:26 +0100197 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
198 // property, otherwise treat if it was specified in the java_header_libs property.
199 if javaSdkLibrarySdkMemberType.IsInstance(child) {
200 return javaSdkLibrarySdkMemberType
201 }
202
203 return javaHeaderLibsSdkMemberType
204}
205
206func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
207 // Export the module added via this dependency tag from the sdk.
208 return true
209}
210
Paul Duffin74431d52021-04-21 14:10:42 +0100211// Avoid having to make stubs content explicitly visible to dependent modules.
212//
213// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
214// with proper dependencies.
215// TODO(b/177892522): Remove this and add needed visibility.
216func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
217}
218
219var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
220var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
221var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
Paul Duffin976b0e52021-04-27 23:20:26 +0100222var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
Paul Duffin74431d52021-04-21 14:10:42 +0100223
Paul Duffin74431d52021-04-21 14:10:42 +0100224// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
225// needed to produce the hidden API monolithic stub flags file.
Paul Duffin31fad802021-06-18 18:14:25 +0100226func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string {
Paul Duffin74431d52021-04-21 14:10:42 +0100227 var publicStubModules []string
228 var systemStubModules []string
229 var testStubModules []string
230 var corePlatformStubModules []string
231
232 if config.AlwaysUsePrebuiltSdks() {
233 // Build configuration mandates using prebuilt stub modules
234 publicStubModules = append(publicStubModules, "sdk_public_current_android")
235 systemStubModules = append(systemStubModules, "sdk_system_current_android")
236 testStubModules = append(testStubModules, "sdk_test_current_android")
237 } else {
238 // Use stub modules built from source
239 publicStubModules = append(publicStubModules, "android_stubs_current")
240 systemStubModules = append(systemStubModules, "android_system_stubs_current")
241 testStubModules = append(testStubModules, "android_test_stubs_current")
242 }
243 // We do not have prebuilts of the core platform api yet
244 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
245
246 // Allow products to define their own stubs for custom product jars that apps can use.
247 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
248 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
249 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
250 if config.IsEnvTrue("EMMA_INSTRUMENT") {
Paul Duffin098c8782021-05-14 10:45:25 +0100251 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
252 // allows everyone access but it is needed to ensure consistent flags between the
253 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
Paul Duffin74431d52021-04-21 14:10:42 +0100254 publicStubModules = append(publicStubModules, "jacoco-stubs")
Paul Duffin098c8782021-05-14 10:45:25 +0100255 systemStubModules = append(systemStubModules, "jacoco-stubs")
256 testStubModules = append(testStubModules, "jacoco-stubs")
Paul Duffin74431d52021-04-21 14:10:42 +0100257 }
258
Paul Duffin31fad802021-06-18 18:14:25 +0100259 m := map[*HiddenAPIScope][]string{}
260 m[PublicHiddenAPIScope] = publicStubModules
261 m[SystemHiddenAPIScope] = systemStubModules
262 m[TestHiddenAPIScope] = testStubModules
263 m[CorePlatformHiddenAPIScope] = corePlatformStubModules
Paul Duffin74431d52021-04-21 14:10:42 +0100264 return m
265}
266
267// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
Paul Duffin31fad802021-06-18 18:14:25 +0100268// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
269// tag to identify the source of the dependency.
270func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) {
Paul Duffin74431d52021-04-21 14:10:42 +0100271 module := ctx.Module()
Paul Duffin31fad802021-06-18 18:14:25 +0100272 for _, apiScope := range hiddenAPIScopes {
273 modules := apiScopeToStubLibModules[apiScope]
274 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...)
Paul Duffin74431d52021-04-21 14:10:42 +0100275 }
276}
277
Paul Duffin74431d52021-04-21 14:10:42 +0100278// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
279// available, or reports an error.
Paul Duffin10931582021-04-25 10:13:54 +0100280func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
281 var dexJar android.Path
282 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
283 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
284 } else if j, ok := module.(UsesLibraryDependency); ok {
285 dexJar = j.DexJarBuildPath()
Paul Duffin74431d52021-04-21 14:10:42 +0100286 } else {
287 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 +0100288 return nil
Paul Duffin74431d52021-04-21 14:10:42 +0100289 }
Paul Duffin10931582021-04-25 10:13:54 +0100290
291 if dexJar == nil {
292 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
293 }
294 return dexJar
Paul Duffin74431d52021-04-21 14:10:42 +0100295}
296
Paul Duffin74431d52021-04-21 14:10:42 +0100297// ruleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
298//
299// The rule is initialized but not built so that the caller can modify it and select an appropriate
300// name.
Paul Duffin1352f7c2021-05-21 22:18:49 +0100301func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
Paul Duffin74431d52021-04-21 14:10:42 +0100302 // Singleton rule which applies hiddenapi on all boot class path dex files.
303 rule := android.NewRuleBuilder(pctx, ctx)
304
305 tempPath := tempPathForRestat(ctx, outputPath)
306
Paul Duffinf1b358c2021-05-17 07:38:47 +0100307 // Find the widest API stubs provided by the fragments on which this depends, if any.
Paul Duffin5cca7c42021-05-26 10:16:01 +0100308 dependencyStubDexJars := input.DependencyStubDexJarsByScope.stubDexJarsForWidestAPIScope()
309
310 // Add widest API stubs from the additional dependencies of this, if any.
311 dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.stubDexJarsForWidestAPIScope()...)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100312
Paul Duffin74431d52021-04-21 14:10:42 +0100313 command := rule.Command().
314 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
315 Text("list").
Paul Duffinf1b358c2021-05-17 07:38:47 +0100316 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100317 FlagForEachInput("--boot-dex=", bootDexJars)
318
Paul Duffin31fad802021-06-18 18:14:25 +0100319 // Iterate over the api scopes in a fixed order.
320 for _, apiScope := range hiddenAPIFlagScopes {
321 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
322 // They will be needed to resolve dependencies from this fragment's stubs to classes in the
323 // other fragment's APIs.
324 var paths android.Paths
325 paths = append(paths, input.DependencyStubDexJarsByScope[apiScope]...)
Paul Duffin5cca7c42021-05-26 10:16:01 +0100326 paths = append(paths, input.AdditionalStubDexJarsByScope[apiScope]...)
Paul Duffin31fad802021-06-18 18:14:25 +0100327 paths = append(paths, input.StubDexJarsByScope[apiScope]...)
Paul Duffin74431d52021-04-21 14:10:42 +0100328 if len(paths) > 0 {
Paul Duffin31fad802021-06-18 18:14:25 +0100329 option := apiScope.hiddenAPIListOption
330 command.FlagWithInputList(option+"=", paths, ":")
Paul Duffin74431d52021-04-21 14:10:42 +0100331 }
332 }
333
334 // Add the output path.
335 command.FlagWithOutput("--out-api-flags=", tempPath)
336
337 commitChangeForRestat(rule, tempPath, outputPath)
338 return rule
339}
340
Paul Duffin46169772021-04-14 15:01:56 +0100341// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
342// information obtained from annotations within the source code in order to create the complete set
343// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100344//
345// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
346// of each property reference a plain text file that contains a java signature per line. The flags
347// for each of those signatures will be updated in a property specific way.
348//
349// The Unsupported_packages property contains a list of paths, each of which is a plain text file
350// with one Java package per line. All members of all classes within that package (but not nested
351// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100352type HiddenAPIFlagFileProperties struct {
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100353 // Marks each signature in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100354 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100355
356 // Marks each signature in the referenced files as being unsupported because it has been removed.
357 // Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100358 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100359
360 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
361 // and low priority.
Paul Duffin702210b2021-04-08 20:12:41 +0100362 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100363
364 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
Paul Duffin702210b2021-04-08 20:12:41 +0100365 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100366
367 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
Paul Duffin702210b2021-04-08 20:12:41 +0100368 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100369
370 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
371 // and low priority. Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100372 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100373
374 // Marks each signature in the referenced files as being blocked.
Paul Duffin702210b2021-04-08 20:12:41 +0100375 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100376
377 // Marks each signature in every package in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100378 Unsupported_packages []string `android:"path"`
379}
380
Paul Duffine3dc6602021-04-14 09:50:43 +0100381type hiddenAPIFlagFileCategory struct {
Paul Duffin524c82c2021-06-09 14:39:28 +0100382 // PropertyName is the name of the property for this category.
383 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100384
Paul Duffincc17bfe2021-04-19 13:21:20 +0100385 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100386 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100387 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100388
389 // commandMutator adds the appropriate command line options for this category to the supplied
390 // command
391 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
392}
393
Paul Duffin32cf58a2021-05-18 16:32:50 +0100394// The flag file category for removed members of the API.
395//
Paul Duffin524c82c2021-06-09 14:39:28 +0100396// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin32cf58a2021-05-18 16:32:50 +0100397// list of removed API members that are generated automatically from the removed.txt files provided
398// by API stubs.
399var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
400 // See HiddenAPIFlagFileProperties.Removed
Paul Duffin524c82c2021-06-09 14:39:28 +0100401 PropertyName: "removed",
Paul Duffin32cf58a2021-05-18 16:32:50 +0100402 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
403 return properties.Removed
404 },
405 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
406 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
407 },
408}
409
Paul Duffin524c82c2021-06-09 14:39:28 +0100410var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
Paul Duffin46169772021-04-14 15:01:56 +0100411 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100412 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100413 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100414 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100415 return properties.Unsupported
416 },
417 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
418 command.FlagWithInput("--unsupported ", path)
419 },
420 },
Paul Duffin32cf58a2021-05-18 16:32:50 +0100421 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100422 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100423 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100424 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100425 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100426 return properties.Max_target_r_low_priority
427 },
428 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
429 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
430 },
431 },
Paul Duffin46169772021-04-14 15:01:56 +0100432 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100433 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100434 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100435 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100436 return properties.Max_target_q
437 },
438 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
439 command.FlagWithInput("--max-target-q ", path)
440 },
441 },
Paul Duffin46169772021-04-14 15:01:56 +0100442 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100443 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100444 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100445 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100446 return properties.Max_target_p
447 },
448 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
449 command.FlagWithInput("--max-target-p ", path)
450 },
451 },
Paul Duffin46169772021-04-14 15:01:56 +0100452 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100453 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100454 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100455 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100456 return properties.Max_target_o_low_priority
457 },
458 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
459 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
460 },
461 },
Paul Duffin46169772021-04-14 15:01:56 +0100462 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100463 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100464 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100465 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100466 return properties.Blocked
467 },
468 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
469 command.FlagWithInput("--blocked ", path)
470 },
471 },
Paul Duffin46169772021-04-14 15:01:56 +0100472 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100473 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100474 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100475 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100476 return properties.Unsupported_packages
477 },
478 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
479 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
480 },
481 },
Paul Duffin702210b2021-04-08 20:12:41 +0100482}
483
Paul Duffin438eb572021-05-21 16:58:23 +0100484// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
485type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
486
487// append appends the supplied flags files to the corresponding category in this map.
488func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100489 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100490 s[category] = append(s[category], other[category]...)
491 }
492}
493
494// dedup removes duplicates in the flag files, while maintaining the order in which they were
495// appended.
496func (s FlagFilesByCategory) dedup() {
497 for category, paths := range s {
498 s[category] = android.FirstUniquePaths(paths)
499 }
500}
501
Paul Duffinaf99afa2021-05-21 22:18:56 +0100502// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100503//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100504// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
505// processing.
506type HiddenAPIInfo struct {
Paul Duffin438eb572021-05-21 16:58:23 +0100507 // FlagFilesByCategory maps from the flag file category to the paths containing information for
508 // that category.
509 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100510
Paul Duffin31fad802021-06-18 18:14:25 +0100511 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes.
512 TransitiveStubDexJarsByScope StubDexJarsByScope
Paul Duffin18cf1972021-05-21 22:46:59 +0100513
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100514 // The output from the hidden API processing needs to be made available to other modules.
515 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100516}
Paul Duffin702210b2021-04-08 20:12:41 +0100517
Paul Duffinf1b358c2021-05-17 07:38:47 +0100518func newHiddenAPIInfo() *HiddenAPIInfo {
519 info := HiddenAPIInfo{
Paul Duffin31fad802021-06-18 18:14:25 +0100520 FlagFilesByCategory: FlagFilesByCategory{},
521 TransitiveStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffinf1b358c2021-05-17 07:38:47 +0100522 }
523 return &info
524}
525
526func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
527 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
528 // this will introduce duplicates so they will be resolved after processing all the fragments.
529 for _, fragment := range fragments {
530 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
531 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
Paul Duffin31fad802021-06-18 18:14:25 +0100532 i.TransitiveStubDexJarsByScope.append(info.TransitiveStubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100533 }
534 }
535
536 // Dedup and sort paths.
Paul Duffin31fad802021-06-18 18:14:25 +0100537 i.TransitiveStubDexJarsByScope.dedupAndSort()
Paul Duffinf1b358c2021-05-17 07:38:47 +0100538}
539
Paul Duffinaf99afa2021-05-21 22:18:56 +0100540var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100541
Paul Duffin31fad802021-06-18 18:14:25 +0100542// StubDexJarsByScope maps a *HiddenAPIScope to the paths to stub dex jars appropriate for that
543// scope. See hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
544type StubDexJarsByScope map[*HiddenAPIScope]android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100545
Paul Duffin31fad802021-06-18 18:14:25 +0100546// append appends the API scope specific stub dex jar args to the corresponding scope in this
Paul Duffin1352f7c2021-05-21 22:18:49 +0100547// map.
Paul Duffin31fad802021-06-18 18:14:25 +0100548func (s StubDexJarsByScope) append(other StubDexJarsByScope) {
549 for _, scope := range hiddenAPIScopes {
550 s[scope] = append(s[scope], other[scope]...)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100551 }
552}
553
554// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
555// deterministic order.
Paul Duffin31fad802021-06-18 18:14:25 +0100556func (s StubDexJarsByScope) dedupAndSort() {
557 for apiScope, paths := range s {
558 s[apiScope] = android.SortedUniquePaths(paths)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100559 }
560}
561
Paul Duffin5cca7c42021-05-26 10:16:01 +0100562// stubDexJarsForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
563// map. The relative width of APIs is determined by their order in hiddenAPIScopes.
564func (s StubDexJarsByScope) stubDexJarsForWidestAPIScope() android.Paths {
565 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
566 apiScope := hiddenAPIScopes[i]
567 stubsForAPIScope := s[apiScope]
568 if len(stubsForAPIScope) != 0 {
569 return stubsForAPIScope
570 }
571 }
572
573 return nil
574}
575
Paul Duffin1352f7c2021-05-21 22:18:49 +0100576// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
577// needed for hidden API flag generation.
578type HiddenAPIFlagInput struct {
579 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
580 // from the stub dex files.
581 FlagFilesByCategory FlagFilesByCategory
582
Paul Duffin31fad802021-06-18 18:14:25 +0100583 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
Paul Duffin1352f7c2021-05-21 22:18:49 +0100584 // the initial flags for each dex member.
Paul Duffin31fad802021-06-18 18:14:25 +0100585 StubDexJarsByScope StubDexJarsByScope
Paul Duffinf1b358c2021-05-17 07:38:47 +0100586
Paul Duffin31fad802021-06-18 18:14:25 +0100587 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
588 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
Paul Duffinf1b358c2021-05-17 07:38:47 +0100589 // fragment on which this depends.
Paul Duffin31fad802021-06-18 18:14:25 +0100590 DependencyStubDexJarsByScope StubDexJarsByScope
Paul Duffin32cf58a2021-05-18 16:32:50 +0100591
Paul Duffin5cca7c42021-05-26 10:16:01 +0100592 // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to
593 // the ones that are obtained from fragments on which this depends.
594 //
595 // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope
596 // as there are not propagated transitively to other fragments that depend on this.
597 AdditionalStubDexJarsByScope StubDexJarsByScope
598
Paul Duffin32cf58a2021-05-18 16:32:50 +0100599 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
600 // specified in the bootclasspath_fragment's stub_libs and contents properties.
601 RemovedTxtFiles android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100602}
603
604// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
605func newHiddenAPIFlagInput() HiddenAPIFlagInput {
606 input := HiddenAPIFlagInput{
Paul Duffin31fad802021-06-18 18:14:25 +0100607 FlagFilesByCategory: FlagFilesByCategory{},
608 StubDexJarsByScope: StubDexJarsByScope{},
609 DependencyStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffin5cca7c42021-05-26 10:16:01 +0100610 AdditionalStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffin1352f7c2021-05-21 22:18:49 +0100611 }
612
613 return input
614}
615
Paul Duffin62370922021-05-23 16:55:37 +0100616// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
617//
618// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
619// appropriate information needed for hidden API processing breaking the build.
620// TODO(b/179354495): Remove this workaround.
621func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
622 // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
623 // required as the whole point of adding something to the bootclasspath fragment is to add it to
624 // the bootclasspath in order to be used by something else in the system. Without any stubs it
625 // cannot do that.
Paul Duffin31fad802021-06-18 18:14:25 +0100626 if len(i.StubDexJarsByScope) == 0 {
Paul Duffin62370922021-05-23 16:55:37 +0100627 return false
628 }
629
630 // Hidden API processing is always enabled in tests.
631 if ctx.Config().TestProductVariables != nil {
632 return true
633 }
634
635 // A module that has fragments should have access to the information it needs in order to perform
636 // hidden API processing.
637 if len(properties.Fragments) != 0 {
638 return true
639 }
640
641 // The art bootclasspath fragment does not depend on any other fragments but already supports
642 // hidden API processing.
643 imageName := proptools.String(properties.Image_name)
644 if imageName == "art" {
645 return true
646 }
647
648 // Disable it for everything else.
649 return false
650}
651
Paul Duffin1352f7c2021-05-21 22:18:49 +0100652// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
653// dependencies added in hiddenAPIAddStubLibDependencies.
654//
655// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
656func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
Paul Duffin31fad802021-06-18 18:14:25 +0100657 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
658 sdkKind := apiScope.sdkKind
659 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100660 if dexJar != nil {
Paul Duffin31fad802021-06-18 18:14:25 +0100661 i.StubDexJarsByScope[apiScope] = append(i.StubDexJarsByScope[apiScope], dexJar)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100662 }
Paul Duffin32cf58a2021-05-18 16:32:50 +0100663
664 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100665 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
Paul Duffin32cf58a2021-05-18 16:32:50 +0100666 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
667 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100668 }
669
670 // If the contents includes any java_sdk_library modules then add them to the stubs.
671 for _, module := range contents {
672 if _, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100673 // Add information for every possible API scope needed by hidden API.
674 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
675 addFromModule(ctx, module, apiScope)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100676 }
677 }
678 }
679
Paul Duffind061d402021-06-07 21:36:01 +0100680 ctx.VisitDirectDeps(func(module android.Module) {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100681 tag := ctx.OtherModuleDependencyTag(module)
682 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100683 apiScope := hiddenAPIStubsTag.apiScope
Paul Duffin5cca7c42021-05-26 10:16:01 +0100684 if hiddenAPIStubsTag.fromAdditionalDependency {
685 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind)
686 if dexJar != nil {
687 i.AdditionalStubDexJarsByScope[apiScope] = append(i.AdditionalStubDexJarsByScope[apiScope], dexJar)
688 }
689 } else {
690 addFromModule(ctx, module, apiScope)
691 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100692 }
693 })
694
695 // Normalize the paths, i.e. remove duplicates and sort.
Paul Duffin31fad802021-06-18 18:14:25 +0100696 i.StubDexJarsByScope.dedupAndSort()
697 i.DependencyStubDexJarsByScope.dedupAndSort()
Paul Duffin32cf58a2021-05-18 16:32:50 +0100698 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100699}
700
701// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
702// supplied properties and stores them in this struct.
703func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100704 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100705 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
706 i.FlagFilesByCategory[category] = paths
707 }
708}
709
Paul Duffin31fad802021-06-18 18:14:25 +0100710func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByScope {
711 transitive := i.DependencyStubDexJarsByScope
712 transitive.append(i.StubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100713 return transitive
714}
715
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100716// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
717// bootclasspath_fragment module.
718type HiddenAPIFlagOutput struct {
719 // The path to the generated stub-flags.csv file.
720 StubFlagsPath android.Path
721
722 // The path to the generated annotation-flags.csv file.
723 AnnotationFlagsPath android.Path
724
725 // The path to the generated metadata.csv file.
726 MetadataPath android.Path
727
728 // The path to the generated index.csv file.
729 IndexPath android.Path
730
731 // The path to the generated all-flags.csv file.
732 AllFlagsPath android.Path
733}
734
Paul Duffin5f148ca2021-06-02 17:24:22 +0100735// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
736// path.
737type bootDexJarByModule map[string]android.Path
738
739// addPath adds the path for a module to the map.
740func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
741 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
742}
743
Paul Duffine5218812021-06-07 13:28:19 +0100744// bootDexJars returns the boot dex jar paths sorted by their keys.
745func (b bootDexJarByModule) bootDexJars() android.Paths {
746 paths := android.Paths{}
747 for _, k := range android.SortedStringKeys(b) {
748 paths = append(paths, b[k])
749 }
750 return paths
751}
752
Paul Duffin7f872162021-06-17 19:33:24 +0100753// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
754// libraries if present.
755func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
756 paths := android.Paths{}
757 for _, k := range android.SortedStringKeys(b) {
758 if k == "jacocoagent" {
759 continue
760 }
761 paths = append(paths, b[k])
762 }
763 return paths
764}
765
Paul Duffine5218812021-06-07 13:28:19 +0100766// HiddenAPIOutput encapsulates the output from the hidden API processing.
767type HiddenAPIOutput struct {
768 HiddenAPIFlagOutput
769
770 // The map from base module name to the path to the encoded boot dex file.
771 EncodedBootDexFilesByModule bootDexJarByModule
772}
773
Paul Duffindfa10832021-05-13 17:31:51 +0100774// pathForValidation creates a path of the same type as the supplied type but with a name of
775// <path>.valid.
776//
777// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
778// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
779func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
780 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
781 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
782}
783
Paul Duffin2fef1362021-04-15 13:32:00 +0100784// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
785// the flags from all the modules, the stub flags, augmented with some additional configuration
786// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100787//
788// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
789// an entry for every single member in the dex implementation jars of the individual modules. Every
790// signature in any of the other files MUST be included in this file.
791//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100792// annotationFlags is the path to the annotation flags file generated from annotation information
793// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100794//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100795// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100796// the annotationFlags.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100797func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
Paul Duffind061d402021-06-07 21:36:01 +0100798 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
Paul Duffin32cf58a2021-05-18 16:32:50 +0100799 flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100800
801 // The file which is used to record that the flags file is valid.
802 var validFile android.WritablePath
803
804 // If there are flag files that have been generated by fragments on which this depends then use
805 // them to validate the flag file generated by the rules created by this method.
Paul Duffin438eb572021-05-21 16:58:23 +0100806 if len(allFlagsPaths) > 0 {
Paul Duffindfa10832021-05-13 17:31:51 +0100807 // The flags file generated by the rule created by this method needs to be validated to ensure
808 // that it is consistent with the flag files generated by the individual fragments.
809
810 validFile = pathForValidation(ctx, outputPath)
811
812 // Create a rule to validate the output from the following rule.
813 rule := android.NewRuleBuilder(pctx, ctx)
814 rule.Command().
815 BuiltTool("verify_overlaps").
816 Input(outputPath).
817 Inputs(allFlagsPaths).
818 // If validation passes then update the file that records that.
819 Text("&& touch").Output(validFile)
820 rule.Build(name+"Validation", desc+" validation")
821 }
822
823 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100824 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100825 rule := android.NewRuleBuilder(pctx, ctx)
826 command := rule.Command().
827 BuiltTool("generate_hiddenapi_lists").
828 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffind061d402021-06-07 21:36:01 +0100829 Inputs(annotationFlagPaths).
Paul Duffin702210b2021-04-08 20:12:41 +0100830 FlagWithOutput("--output ", tempPath)
831
Paul Duffine3dc6602021-04-14 09:50:43 +0100832 // Add the options for the different categories of flag files.
Paul Duffin524c82c2021-06-09 14:39:28 +0100833 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100834 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100835 for _, path := range paths {
836 category.commandMutator(command, path)
837 }
Paul Duffin702210b2021-04-08 20:12:41 +0100838 }
839
Paul Duffin32cf58a2021-05-18 16:32:50 +0100840 // If available then pass the automatically generated file containing dex signatures of removed
841 // API members to the rule so they can be marked as removed.
842 if generatedRemovedDexSignatures.Valid() {
843 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
844 }
845
Paul Duffin702210b2021-04-08 20:12:41 +0100846 commitChangeForRestat(rule, tempPath, outputPath)
847
Paul Duffindfa10832021-05-13 17:31:51 +0100848 if validFile != nil {
849 // Add the file that indicates that the file generated by this is valid.
850 //
851 // This will cause the validation rule above to be run any time that the output of this rule
852 // changes but the validation will run in parallel with other rules that depend on this file.
853 command.Validation(validFile)
854 }
855
Paul Duffin2fef1362021-04-15 13:32:00 +0100856 rule.Build(name, desc)
857}
858
Paul Duffine5218812021-06-07 13:28:19 +0100859// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
860// bootclasspath and then encode the flags into the boot dex files.
Paul Duffin2fef1362021-04-15 13:32:00 +0100861//
862// It takes:
863// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
864// * The list of modules that are the contents of the fragment.
865// * The additional manually curated flag files to use.
866//
867// It generates:
868// * stub-flags.csv
869// * annotation-flags.csv
870// * metadata.csv
871// * index.csv
872// * all-flags.csv
Paul Duffine5218812021-06-07 13:28:19 +0100873// * encoded boot dex files
874func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +0100875 hiddenApiSubDir := "modular-hiddenapi"
876
Paul Duffine5218812021-06-07 13:28:19 +0100877 // Gather information about the boot dex files for the boot libraries provided by this fragment.
878 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100879
880 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +0100881 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffine5218812021-06-07 13:28:19 +0100882 rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input)
Paul Duffin2fef1362021-04-15 13:32:00 +0100883 rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
884
Paul Duffin537ea3d2021-05-14 10:38:00 +0100885 // Extract the classes jars from the contents.
Paul Duffindd5993f2021-06-10 10:18:22 +0100886 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100887
Paul Duffin2fef1362021-04-15 13:32:00 +0100888 // Generate the set of flags from the annotations in the source code.
889 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100890 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100891
892 // Generate the metadata from the annotations in the source code.
893 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100894 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100895
Paul Duffin537ea3d2021-05-14 10:38:00 +0100896 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +0100897 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100898 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100899
Paul Duffinaf99afa2021-05-21 22:18:56 +0100900 // 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 +0100901 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
902 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin32cf58a2021-05-18 16:32:50 +0100903 // signatures, see the combined-removed-dex module. This does that automatically by using the
904 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
905 // stub_libs and contents properties of a bootclasspath_fragment.
906 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +0100907
908 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
909 // files.
Paul Duffine5218812021-06-07 13:28:19 +0100910 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
Paul Duffind061d402021-06-07 21:36:01 +0100911 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
Paul Duffine5218812021-06-07 13:28:19 +0100912
913 // Encode the flags into the boot dex files.
914 encodedBootDexJarsByModule := map[string]android.Path{}
915 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
916 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
917 bootDexInfo := bootDexInfoByModule[name]
918 unencodedDex := bootDexInfo.path
919 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
920 encodedBootDexJarsByModule[name] = encodedDex
921 }
Paul Duffin2fef1362021-04-15 13:32:00 +0100922
923 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffine5218812021-06-07 13:28:19 +0100924 output := HiddenAPIOutput{
925 HiddenAPIFlagOutput: HiddenAPIFlagOutput{
926 StubFlagsPath: stubFlagsCSV,
927 AnnotationFlagsPath: annotationFlagsCSV,
928 MetadataPath: metadataCSV,
929 IndexPath: indexCSV,
930 AllFlagsPath: allFlagsCSV,
931 },
932 EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100933 }
934 return &output
Paul Duffin702210b2021-04-08 20:12:41 +0100935}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100936
Paul Duffin32cf58a2021-05-18 16:32:50 +0100937func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
938 if len(removedTxtFiles) == 0 {
939 return android.OptionalPath{}
940 }
941
942 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
943
944 rule := android.NewRuleBuilder(pctx, ctx)
945 rule.Command().
946 BuiltTool("metalava").
947 Flag("--no-banner").
948 Inputs(removedTxtFiles).
949 FlagWithOutput("--dex-api ", output)
950 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
951 return android.OptionalPathForPath(output)
952}
953
Paul Duffindd5993f2021-06-10 10:18:22 +0100954// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffine5218812021-06-07 13:28:19 +0100955func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
956 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100957 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +0100958 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
959 if hiddenAPIModule == nil {
960 continue
961 }
Paul Duffine5218812021-06-07 13:28:19 +0100962 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
963 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100964 }
965 return bootDexJars
966}
967
Paul Duffindd5993f2021-06-10 10:18:22 +0100968func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
969 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
970 return hiddenAPIModule
971 } else if _, ok := module.(*DexImport); ok {
972 // Ignore this for the purposes of hidden API processing
973 } else {
974 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
975 }
976
977 return nil
978}
979
Paul Duffine5218812021-06-07 13:28:19 +0100980// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
981type bootDexInfo struct {
982 // The path to the dex jar that has not had hidden API flags encoded into it.
983 path android.Path
984
985 // Indicates whether the dex jar needs uncompressing before encoding.
986 uncompressDex bool
987}
988
989// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
990// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
991type bootDexInfoByModule map[string]bootDexInfo
992
993// bootDexJars returns the boot dex jar paths sorted by their keys.
994func (b bootDexInfoByModule) bootDexJars() android.Paths {
995 paths := android.Paths{}
996 for _, m := range android.SortedStringKeys(b) {
997 paths = append(paths, b[m].path)
998 }
999 return paths
1000}
1001
1002// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
1003// each of the supplied modules which must implement hiddenAPIModule.
1004func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
1005 bootDexJarsByModule := bootDexInfoByModule{}
1006 for _, module := range contents {
1007 hiddenAPIModule := module.(hiddenAPIModule)
1008 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
1009 bootDexJarsByModule[module.Name()] = bootDexInfo{
1010 path: bootDexJar,
1011 uncompressDex: *hiddenAPIModule.uncompressDex(),
1012 }
1013 }
1014
1015 return bootDexJarsByModule
1016}
1017
1018// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
1019//
1020// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
1021// create a fake path and either report an error immediately or defer reporting of the error until
1022// the path is actually used.
1023func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
1024 bootDexJar := module.bootDexJar()
1025 if bootDexJar == nil {
1026 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
1027 bootDexJar = fake
1028
1029 handleMissingDexBootFile(ctx, module, fake)
1030 }
1031 return bootDexJar
1032}
1033
Paul Duffindd5993f2021-06-10 10:18:22 +01001034// extractClassesJarsFromModules extracts the class jars from the supplied modules.
1035func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +01001036 classesJars := android.Paths{}
1037 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +01001038 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001039 }
1040 return classesJars
1041}
Paul Duffin5f148ca2021-06-02 17:24:22 +01001042
Paul Duffindd5993f2021-06-10 10:18:22 +01001043// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
1044func retrieveClassesJarsFromModule(module android.Module) android.Paths {
1045 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
1046 return hiddenAPIModule.classesJars()
1047 }
1048
1049 return nil
1050}
1051
Paul Duffin5f148ca2021-06-02 17:24:22 +01001052// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
1053// Soong but should instead only be reported in ninja if the file is actually built.
1054func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
1055 // TODO(b/179354495): Remove this workaround when it is unnecessary.
1056 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
1057 // create a fake one that will cause a build error only if it is used.
1058 if ctx.Config().AlwaysUsePrebuiltSdks() {
1059 return true
1060 }
1061
Paul Duffine5218812021-06-07 13:28:19 +01001062 // Any missing dependency should be allowed.
1063 if ctx.Config().AllowMissingDependencies() {
1064 return true
1065 }
1066
Paul Duffin5f148ca2021-06-02 17:24:22 +01001067 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
1068 //
1069 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
1070 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
1071 // but unfortunately, due to b/187910671 it does.
1072 //
1073 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
1074 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
1075 // has an APEX variant not a platform variant.
1076 //
1077 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
1078 // provide a boot dex jar:
1079 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
1080 // does not have an APEX variant and only has a platform variant and neither do its content
1081 // modules.
1082 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
1083 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
1084 // of an apex they cannot provide a boot dex jar.
1085 //
1086 // The first case causes problems when the affected prebuilt modules are preferred but that is an
1087 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
1088 // complete. The second case is used for building targets that do not use boot dex jars and so
1089 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
1090 // That is handled above.
1091 //
1092 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
1093 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
1094 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
1095 // that if the library can be part of an APEX then it is the APEX variant that is used.
1096 //
1097 // This check handles the slightly different requirements of the bootclasspath_fragment and
1098 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
1099 // a prebuilt modules that has other variants which are part of an APEX.
1100 //
1101 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
1102 if android.IsModulePrebuilt(module) {
1103 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
1104 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
1105 if apexInfo.IsForPlatform() {
1106 return true
1107 }
1108 }
1109 }
1110
1111 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
1112 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
1113 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
1114 // failures missing boot dex jars need to be deferred.
1115 if android.IsModuleInVersionedSdk(ctx.Module()) {
1116 return true
1117 }
1118
1119 return false
1120}
1121
1122// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
1123// file depending on the value returned from deferReportingMissingBootDexJar.
1124func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
1125 if deferReportingMissingBootDexJar(ctx, module) {
1126 // Create an error rule that pretends to create the output file but will actually fail if it
1127 // is run.
1128 ctx.Build(pctx, android.BuildParams{
1129 Rule: android.ErrorRule,
1130 Output: fake,
1131 Args: map[string]string{
1132 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
1133 },
1134 })
1135 } else {
1136 ctx.ModuleErrorf("module %s does not provide a dex jar", module)
1137 }
1138}
1139
1140// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
1141// DexJarBuildPath() method.
1142//
1143// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
1144// However, under certain conditions, e.g. errors, or special build configurations it will return
1145// a path to a fake file.
1146func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
1147 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
1148 if bootDexJar == nil {
1149 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
1150 bootDexJar = fake
1151
1152 handleMissingDexBootFile(ctx, module, fake)
1153 }
1154 return bootDexJar
1155}
1156
1157// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
1158func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1159 encodedDexJarsByModuleName := bootDexJarByModule{}
1160 for _, module := range contents {
1161 path := retrieveEncodedBootDexJarFromModule(ctx, module)
1162 encodedDexJarsByModuleName.addPath(module, path)
1163 }
1164 return encodedDexJarsByModuleName
1165}