blob: 08e684c3b6d0f05a5b8cc0d268e0fa167198c720 [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"
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +010022
Paul Duffin9b381ef2021-04-08 23:01:37 +010023 "github.com/google/blueprint"
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 Duffinf7b3d0d2021-09-02 14:29:21 +0100222var _ android.SdkMemberDependencyTag = 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 {
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +0100281 var dexJar OptionalDexJarPath
Paul Duffin10931582021-04-25 10:13:54 +0100282 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
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +0100291 if !dexJar.Valid() {
292 ctx.ModuleErrorf("dependency %s does not provide a dex jar: %s", module, dexJar.InvalidReason())
293 return nil
Paul Duffin10931582021-04-25 10:13:54 +0100294 }
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +0100295 return dexJar.Path()
Paul Duffin74431d52021-04-21 14:10:42 +0100296}
297
Paul Duffinbd88c882022-04-07 23:32:19 +0100298// HIDDENAPI_STUB_FLAGS_IMPL_FLAGS is the set of flags that identify implementation only signatures,
299// i.e. those signatures that are not part of any API (including the hidden API).
300var HIDDENAPI_STUB_FLAGS_IMPL_FLAGS = []string{}
301
302var HIDDENAPI_FLAGS_CSV_IMPL_FLAGS = []string{"blocked"}
303
Paul Duffin4539a372021-06-23 23:20:43 +0100304// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
Paul Duffin74431d52021-04-21 14:10:42 +0100305//
306// The rule is initialized but not built so that the caller can modify it and select an appropriate
307// name.
Paul Duffin67b9d612021-07-21 17:38:47 +0100308func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, stubFlagSubsets SignatureCsvSubsets) {
Paul Duffin74431d52021-04-21 14:10:42 +0100309 // Singleton rule which applies hiddenapi on all boot class path dex files.
310 rule := android.NewRuleBuilder(pctx, ctx)
311
312 tempPath := tempPathForRestat(ctx, outputPath)
313
Paul Duffinf1b358c2021-05-17 07:38:47 +0100314 // Find the widest API stubs provided by the fragments on which this depends, if any.
Paul Duffind2b1e0c2021-06-27 20:53:39 +0100315 dependencyStubDexJars := input.DependencyStubDexJarsByScope.StubDexJarsForWidestAPIScope()
Paul Duffin5cca7c42021-05-26 10:16:01 +0100316
317 // Add widest API stubs from the additional dependencies of this, if any.
Paul Duffind2b1e0c2021-06-27 20:53:39 +0100318 dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.StubDexJarsForWidestAPIScope()...)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100319
Paul Duffin74431d52021-04-21 14:10:42 +0100320 command := rule.Command().
321 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
322 Text("list").
Paul Duffinf1b358c2021-05-17 07:38:47 +0100323 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100324 FlagForEachInput("--boot-dex=", bootDexJars)
325
Paul Duffin156b5d32021-06-24 23:06:52 +0100326 // If no module stub flags paths are provided then this must be being called for a
327 // bootclasspath_fragment and not the whole platform_bootclasspath.
Paul Duffin67b9d612021-07-21 17:38:47 +0100328 if stubFlagSubsets == nil {
Paul Duffin156b5d32021-06-24 23:06:52 +0100329 // This is being run on a fragment of the bootclasspath.
330 command.Flag("--fragment")
331 }
332
Paul Duffin31fad802021-06-18 18:14:25 +0100333 // Iterate over the api scopes in a fixed order.
334 for _, apiScope := range hiddenAPIFlagScopes {
335 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
336 // They will be needed to resolve dependencies from this fragment's stubs to classes in the
337 // other fragment's APIs.
338 var paths android.Paths
Paul Duffin280a31a2021-06-27 20:28:29 +0100339 paths = append(paths, input.DependencyStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
340 paths = append(paths, input.AdditionalStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
341 paths = append(paths, input.StubDexJarsByScope.StubDexJarsForScope(apiScope)...)
Paul Duffin74431d52021-04-21 14:10:42 +0100342 if len(paths) > 0 {
Paul Duffin31fad802021-06-18 18:14:25 +0100343 option := apiScope.hiddenAPIListOption
344 command.FlagWithInputList(option+"=", paths, ":")
Paul Duffin74431d52021-04-21 14:10:42 +0100345 }
346 }
347
348 // Add the output path.
349 command.FlagWithOutput("--out-api-flags=", tempPath)
350
Paul Duffin2e880972021-06-23 23:29:09 +0100351 // If there are stub flag files that have been generated by fragments on which this depends then
352 // use them to validate the stub flag file generated by the rules created by this method.
Paul Duffin67b9d612021-07-21 17:38:47 +0100353 if len(stubFlagSubsets) > 0 {
Paul Duffinbd88c882022-04-07 23:32:19 +0100354 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets,
355 HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
Paul Duffin2e880972021-06-23 23:29:09 +0100356
357 // Add the file that indicates that the file generated by this is valid.
358 //
359 // This will cause the validation rule above to be run any time that the output of this rule
360 // changes but the validation will run in parallel with other rules that depend on this file.
361 command.Validation(validFile)
362 }
363
Paul Duffin74431d52021-04-21 14:10:42 +0100364 commitChangeForRestat(rule, tempPath, outputPath)
Paul Duffin4539a372021-06-23 23:20:43 +0100365
366 rule.Build(name, desc)
Paul Duffin74431d52021-04-21 14:10:42 +0100367}
368
Paul Duffin46169772021-04-14 15:01:56 +0100369// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
370// information obtained from annotations within the source code in order to create the complete set
371// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100372//
373// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
374// of each property reference a plain text file that contains a java signature per line. The flags
375// for each of those signatures will be updated in a property specific way.
376//
377// The Unsupported_packages property contains a list of paths, each of which is a plain text file
378// with one Java package per line. All members of all classes within that package (but not nested
379// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100380type HiddenAPIFlagFileProperties struct {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000381 Hidden_api struct {
382 // Marks each signature in the referenced files as being unsupported.
383 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100384
Paul Duffin9b61abb2022-07-27 16:16:54 +0000385 // Marks each signature in the referenced files as being unsupported because it has been
386 // removed. Any conflicts with other flags are ignored.
387 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100388
Paul Duffin9b61abb2022-07-27 16:16:54 +0000389 // Marks each signature in the referenced files as being supported only for
390 // targetSdkVersion <= R and low priority.
391 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100392
Paul Duffin9b61abb2022-07-27 16:16:54 +0000393 // Marks each signature in the referenced files as being supported only for
394 // targetSdkVersion <= Q.
395 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100396
Paul Duffin9b61abb2022-07-27 16:16:54 +0000397 // Marks each signature in the referenced files as being supported only for
398 // targetSdkVersion <= P.
399 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100400
Paul Duffin9b61abb2022-07-27 16:16:54 +0000401 // Marks each signature in the referenced files as being supported only for
402 // targetSdkVersion <= O
403 // and low priority. Any conflicts with other flags are ignored.
404 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100405
Paul Duffin9b61abb2022-07-27 16:16:54 +0000406 // Marks each signature in the referenced files as being blocked.
407 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100408
Paul Duffin9b61abb2022-07-27 16:16:54 +0000409 // Marks each signature in every package in the referenced files as being unsupported.
410 Unsupported_packages []string `android:"path"`
411 }
Paul Duffin702210b2021-04-08 20:12:41 +0100412}
413
Paul Duffine3dc6602021-04-14 09:50:43 +0100414type hiddenAPIFlagFileCategory struct {
Paul Duffin524c82c2021-06-09 14:39:28 +0100415 // PropertyName is the name of the property for this category.
416 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100417
Paul Duffincc17bfe2021-04-19 13:21:20 +0100418 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100419 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100420 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100421
422 // commandMutator adds the appropriate command line options for this category to the supplied
423 // command
424 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
425}
426
Paul Duffin32cf58a2021-05-18 16:32:50 +0100427// The flag file category for removed members of the API.
428//
Paul Duffin524c82c2021-06-09 14:39:28 +0100429// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin32cf58a2021-05-18 16:32:50 +0100430// list of removed API members that are generated automatically from the removed.txt files provided
431// by API stubs.
432var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
433 // See HiddenAPIFlagFileProperties.Removed
Paul Duffin524c82c2021-06-09 14:39:28 +0100434 PropertyName: "removed",
Paul Duffin32cf58a2021-05-18 16:32:50 +0100435 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000436 return properties.Hidden_api.Removed
Paul Duffin32cf58a2021-05-18 16:32:50 +0100437 },
438 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
439 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
440 },
441}
442
Paul Duffin3f1ae0b2022-07-27 16:27:42 +0000443type hiddenAPIFlagFileCategories []*hiddenAPIFlagFileCategory
444
445func (c hiddenAPIFlagFileCategories) byProperty(name string) *hiddenAPIFlagFileCategory {
446 for _, category := range c {
447 if category.PropertyName == name {
448 return category
449 }
450 }
451 panic(fmt.Errorf("no category exists with property name %q in %v", name, c))
452}
453
454var HiddenAPIFlagFileCategories = hiddenAPIFlagFileCategories{
Paul Duffin46169772021-04-14 15:01:56 +0100455 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100456 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100457 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100458 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000459 return properties.Hidden_api.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100460 },
461 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
462 command.FlagWithInput("--unsupported ", path)
463 },
464 },
Paul Duffin32cf58a2021-05-18 16:32:50 +0100465 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100466 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100467 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100468 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100469 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000470 return properties.Hidden_api.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100471 },
472 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
473 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
474 },
475 },
Paul Duffin46169772021-04-14 15:01:56 +0100476 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100477 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100478 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100479 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000480 return properties.Hidden_api.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100481 },
482 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
483 command.FlagWithInput("--max-target-q ", path)
484 },
485 },
Paul Duffin46169772021-04-14 15:01:56 +0100486 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100487 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100488 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100489 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000490 return properties.Hidden_api.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100491 },
492 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
493 command.FlagWithInput("--max-target-p ", path)
494 },
495 },
Paul Duffin46169772021-04-14 15:01:56 +0100496 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100497 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100498 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100499 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000500 return properties.Hidden_api.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100501 },
502 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
503 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
504 },
505 },
Paul Duffin46169772021-04-14 15:01:56 +0100506 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100507 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100508 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100509 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000510 return properties.Hidden_api.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100511 },
512 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
513 command.FlagWithInput("--blocked ", path)
514 },
515 },
Paul Duffin46169772021-04-14 15:01:56 +0100516 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100517 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100518 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100519 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffin9b61abb2022-07-27 16:16:54 +0000520 return properties.Hidden_api.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100521 },
522 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
523 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
524 },
525 },
Paul Duffin702210b2021-04-08 20:12:41 +0100526}
527
Paul Duffin438eb572021-05-21 16:58:23 +0100528// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
529type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
530
Paul Duffin3f1ae0b2022-07-27 16:27:42 +0000531// append the supplied flags files to the corresponding category in this map.
Paul Duffin438eb572021-05-21 16:58:23 +0100532func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100533 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100534 s[category] = append(s[category], other[category]...)
535 }
536}
537
Paul Duffin3f1ae0b2022-07-27 16:27:42 +0000538// sort the paths for each category in this map.
539func (s FlagFilesByCategory) sort() {
540 for category, value := range s {
541 s[category] = android.SortedUniquePaths(value)
542 }
543}
544
Paul Duffinaf99afa2021-05-21 22:18:56 +0100545// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100546//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100547// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
548// processing.
549type HiddenAPIInfo struct {
Paul Duffin438eb572021-05-21 16:58:23 +0100550 // FlagFilesByCategory maps from the flag file category to the paths containing information for
551 // that category.
552 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100553
Paul Duffin280a31a2021-06-27 20:28:29 +0100554 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes provided by
555 // this fragment and the fragments on which this depends.
556 TransitiveStubDexJarsByScope StubDexJarsByModule
Paul Duffin18cf1972021-05-21 22:46:59 +0100557
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100558 // The output from the hidden API processing needs to be made available to other modules.
559 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100560}
Paul Duffin702210b2021-04-08 20:12:41 +0100561
Paul Duffinf1b358c2021-05-17 07:38:47 +0100562func newHiddenAPIInfo() *HiddenAPIInfo {
563 info := HiddenAPIInfo{
Paul Duffin31fad802021-06-18 18:14:25 +0100564 FlagFilesByCategory: FlagFilesByCategory{},
Paul Duffin280a31a2021-06-27 20:28:29 +0100565 TransitiveStubDexJarsByScope: StubDexJarsByModule{},
Paul Duffinf1b358c2021-05-17 07:38:47 +0100566 }
567 return &info
568}
569
570func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
571 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
572 // this will introduce duplicates so they will be resolved after processing all the fragments.
573 for _, fragment := range fragments {
574 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
575 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
Paul Duffin280a31a2021-06-27 20:28:29 +0100576 i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100577 }
578 }
Paul Duffinf1b358c2021-05-17 07:38:47 +0100579}
580
Paul Duffin191be3a2021-08-10 16:14:16 +0100581// StubFlagSubset returns a SignatureCsvSubset that contains a path to a filtered-stub-flags.csv
582// file and a path to a signature-patterns.csv file that defines a subset of the monolithic stub
583// flags file, i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
Paul Duffin67b9d612021-07-21 17:38:47 +0100584func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
Paul Duffin191be3a2021-08-10 16:14:16 +0100585 return SignatureCsvSubset{i.FilteredStubFlagsPath, i.SignaturePatternsPath}
Paul Duffin67b9d612021-07-21 17:38:47 +0100586}
587
Paul Duffin191be3a2021-08-10 16:14:16 +0100588// FlagSubset returns a SignatureCsvSubset that contains a path to a filtered-flags.csv file and a
Paul Duffin67b9d612021-07-21 17:38:47 +0100589// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
590// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
591func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
Paul Duffin191be3a2021-08-10 16:14:16 +0100592 return SignatureCsvSubset{i.FilteredFlagsPath, i.SignaturePatternsPath}
Paul Duffin67b9d612021-07-21 17:38:47 +0100593}
594
Paul Duffinaf99afa2021-05-21 22:18:56 +0100595var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100596
Paul Duffin280a31a2021-06-27 20:28:29 +0100597// ModuleStubDexJars contains the stub dex jars provided by a single module.
598//
599// It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
600// hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
601type ModuleStubDexJars map[*HiddenAPIScope]android.Path
Paul Duffin1352f7c2021-05-21 22:18:49 +0100602
Paul Duffin280a31a2021-06-27 20:28:29 +0100603// stubDexJarForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
Paul Duffin1352f7c2021-05-21 22:18:49 +0100604// map.
Paul Duffin280a31a2021-06-27 20:28:29 +0100605//
606// The relative width of APIs is determined by their order in hiddenAPIScopes.
607func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100608 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
609 apiScope := hiddenAPIScopes[i]
Paul Duffin280a31a2021-06-27 20:28:29 +0100610 if stubsForAPIScope, ok := s[apiScope]; ok {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100611 return stubsForAPIScope
612 }
613 }
614
615 return nil
616}
617
Paul Duffin280a31a2021-06-27 20:28:29 +0100618// StubDexJarsByModule contains the stub dex jars provided by a set of modules.
619//
620// It maps a module name to the path to the stub dex jars provided by that module.
621type StubDexJarsByModule map[string]ModuleStubDexJars
622
623// addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope.
624func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) {
625 name := android.RemoveOptionalPrebuiltPrefix(module.Name())
Paul Duffin3f0290e2021-06-30 18:25:36 +0100626
627 // Each named module provides one dex jar for each scope. However, in some cases different API
628 // versions of a single classes are provided by separate modules. e.g. the core platform
629 // version of java.lang.Object is provided by the legacy.art.module.platform.api module but the
630 // public version is provided by the art.module.public.api module. In those cases it is necessary
631 // to treat all those modules as they were the same name, otherwise it will result in multiple
632 // definitions of a single class being passed to hidden API processing which will cause an error.
Paul Duffin280a31a2021-06-27 20:28:29 +0100633 if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
634 // Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
635 // java_sdk_library.
636 // TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
637 name = "android-non-updatable"
638 } else if name == "legacy.art.module.platform.api" {
639 // Treat legacy.art.module.platform.api as if it was an API scope provided by the
640 // art.module.public.api java_sdk_library which will be the case once the former has been
641 // migrated to a module_lib API.
642 name = "art.module.public.api"
643 } else if name == "legacy.i18n.module.platform.api" {
644 // Treat legacy.i18n.module.platform.api as if it was an API scope provided by the
645 // i18n.module.public.api java_sdk_library which will be the case once the former has been
646 // migrated to a module_lib API.
647 name = "i18n.module.public.api"
648 } else if name == "conscrypt.module.platform.api" {
649 // Treat conscrypt.module.platform.api as if it was an API scope provided by the
650 // conscrypt.module.public.api java_sdk_library which will be the case once the former has been
651 // migrated to a module_lib API.
652 name = "conscrypt.module.public.api"
Paul Duffin3f0290e2021-06-30 18:25:36 +0100653 } else if d, ok := module.(SdkLibraryComponentDependency); ok {
654 sdkLibraryName := d.SdkLibraryName()
655 if sdkLibraryName != nil {
656 // The module is a component of a java_sdk_library so use the name of the java_sdk_library.
657 // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then
658 // use `foo` as the name.
659 name = *sdkLibraryName
660 }
Paul Duffin280a31a2021-06-27 20:28:29 +0100661 }
662 stubDexJarsByScope := s[name]
663 if stubDexJarsByScope == nil {
664 stubDexJarsByScope = ModuleStubDexJars{}
665 s[name] = stubDexJarsByScope
666 }
667 stubDexJarsByScope[scope] = stubDexJar
668}
669
670// addStubDexJarsByModule adds the stub dex jars in the supplied StubDexJarsByModule to this map.
671func (s StubDexJarsByModule) addStubDexJarsByModule(other StubDexJarsByModule) {
672 for module, stubDexJarsByScope := range other {
673 s[module] = stubDexJarsByScope
674 }
675}
676
677// StubDexJarsForWidestAPIScope returns a list of stub dex jars containing the widest API scope
678// provided by each module.
679//
680// The relative width of APIs is determined by their order in hiddenAPIScopes.
681func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
682 stubDexJars := android.Paths{}
683 modules := android.SortedStringKeys(s)
684 for _, module := range modules {
685 stubDexJarsByScope := s[module]
686
687 stubDexJars = append(stubDexJars, stubDexJarsByScope.stubDexJarForWidestAPIScope())
688 }
689
690 return stubDexJars
691}
692
693// StubDexJarsForScope returns a list of stub dex jars containing the stub dex jars provided by each
694// module for the specified scope.
695//
696// If a module does not provide a stub dex jar for the supplied scope then it does not contribute to
697// the returned list.
698func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths {
699 stubDexJars := android.Paths{}
700 modules := android.SortedStringKeys(s)
701 for _, module := range modules {
702 stubDexJarsByScope := s[module]
703 // Not every module will have the same set of
704 if jars, ok := stubDexJarsByScope[scope]; ok {
705 stubDexJars = append(stubDexJars, jars)
706 }
707 }
708
709 return stubDexJars
710}
711
Paul Duffin1e9e9382022-07-27 15:55:06 +0000712type HiddenAPIPropertyInfo struct {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100713 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
714 // from the stub dex files.
715 FlagFilesByCategory FlagFilesByCategory
716
Paul Duffin1e9e9382022-07-27 15:55:06 +0000717 // See HiddenAPIFlagFileProperties.Package_prefixes
718 PackagePrefixes []string
719
720 // See HiddenAPIFlagFileProperties.Single_packages
721 SinglePackages []string
722
723 // See HiddenAPIFlagFileProperties.Split_packages
724 SplitPackages []string
725}
726
Paul Duffin3f1ae0b2022-07-27 16:27:42 +0000727var hiddenAPIPropertyInfoProvider = blueprint.NewProvider(HiddenAPIPropertyInfo{})
728
Paul Duffin1e9e9382022-07-27 15:55:06 +0000729// newHiddenAPIPropertyInfo creates a new initialized HiddenAPIPropertyInfo struct.
730func newHiddenAPIPropertyInfo() HiddenAPIPropertyInfo {
731 return HiddenAPIPropertyInfo{
732 FlagFilesByCategory: FlagFilesByCategory{},
733 }
734}
735
736// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
737// supplied properties and stores them in this struct.
738func (i *HiddenAPIPropertyInfo) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
739 for _, category := range HiddenAPIFlagFileCategories {
740 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
741 i.FlagFilesByCategory[category] = paths
742 }
743}
744
745// extractPackageRulesFromProperties extracts the package rules that are specified in the supplied
746// properties and stores them in this struct.
747func (i *HiddenAPIPropertyInfo) extractPackageRulesFromProperties(p *HiddenAPIPackageProperties) {
748 i.PackagePrefixes = p.Hidden_api.Package_prefixes
749 i.SinglePackages = p.Hidden_api.Single_packages
750 i.SplitPackages = p.Hidden_api.Split_packages
751}
752
Paul Duffin3f1ae0b2022-07-27 16:27:42 +0000753func (i *HiddenAPIPropertyInfo) gatherPropertyInfo(ctx android.ModuleContext, contents []android.Module) {
754 for _, module := range contents {
755 if ctx.OtherModuleHasProvider(module, hiddenAPIPropertyInfoProvider) {
756 info := ctx.OtherModuleProvider(module, hiddenAPIPropertyInfoProvider).(HiddenAPIPropertyInfo)
757 i.FlagFilesByCategory.append(info.FlagFilesByCategory)
758 i.PackagePrefixes = append(i.PackagePrefixes, info.PackagePrefixes...)
759 i.SinglePackages = append(i.SinglePackages, info.SinglePackages...)
760 i.SplitPackages = append(i.SplitPackages, info.SplitPackages...)
761 }
762 }
763
764 // Dedup and sort the information to ensure consistent builds.
765 i.FlagFilesByCategory.sort()
766 i.PackagePrefixes = android.SortedUniqueStrings(i.PackagePrefixes)
767 i.SinglePackages = android.SortedUniqueStrings(i.SinglePackages)
768 i.SplitPackages = android.SortedUniqueStrings(i.SplitPackages)
769}
770
Paul Duffin1e9e9382022-07-27 15:55:06 +0000771// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
772// needed for hidden API flag generation.
773type HiddenAPIFlagInput struct {
774 HiddenAPIPropertyInfo
775
Paul Duffin31fad802021-06-18 18:14:25 +0100776 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
Paul Duffin1352f7c2021-05-21 22:18:49 +0100777 // the initial flags for each dex member.
Paul Duffin280a31a2021-06-27 20:28:29 +0100778 StubDexJarsByScope StubDexJarsByModule
Paul Duffinf1b358c2021-05-17 07:38:47 +0100779
Paul Duffin31fad802021-06-18 18:14:25 +0100780 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
781 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
Paul Duffinf1b358c2021-05-17 07:38:47 +0100782 // fragment on which this depends.
Paul Duffin280a31a2021-06-27 20:28:29 +0100783 DependencyStubDexJarsByScope StubDexJarsByModule
Paul Duffin32cf58a2021-05-18 16:32:50 +0100784
Paul Duffin5cca7c42021-05-26 10:16:01 +0100785 // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to
786 // the ones that are obtained from fragments on which this depends.
787 //
788 // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope
789 // as there are not propagated transitively to other fragments that depend on this.
Paul Duffin280a31a2021-06-27 20:28:29 +0100790 AdditionalStubDexJarsByScope StubDexJarsByModule
Paul Duffin5cca7c42021-05-26 10:16:01 +0100791
Paul Duffin32cf58a2021-05-18 16:32:50 +0100792 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
793 // specified in the bootclasspath_fragment's stub_libs and contents properties.
794 RemovedTxtFiles android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100795}
796
Paul Duffin1e9e9382022-07-27 15:55:06 +0000797// newHiddenAPIFlagInput creates a new initialized HiddenAPIFlagInput struct.
Paul Duffin1352f7c2021-05-21 22:18:49 +0100798func newHiddenAPIFlagInput() HiddenAPIFlagInput {
799 input := HiddenAPIFlagInput{
Paul Duffin1e9e9382022-07-27 15:55:06 +0000800 HiddenAPIPropertyInfo: newHiddenAPIPropertyInfo(),
Paul Duffin280a31a2021-06-27 20:28:29 +0100801 StubDexJarsByScope: StubDexJarsByModule{},
802 DependencyStubDexJarsByScope: StubDexJarsByModule{},
803 AdditionalStubDexJarsByScope: StubDexJarsByModule{},
Paul Duffin1352f7c2021-05-21 22:18:49 +0100804 }
805
806 return input
807}
808
809// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
810// dependencies added in hiddenAPIAddStubLibDependencies.
811//
812// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
813func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
Paul Duffin31fad802021-06-18 18:14:25 +0100814 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
815 sdkKind := apiScope.sdkKind
816 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100817 if dexJar != nil {
Paul Duffin280a31a2021-06-27 20:28:29 +0100818 i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100819 }
Paul Duffin32cf58a2021-05-18 16:32:50 +0100820
821 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100822 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
Paul Duffin32cf58a2021-05-18 16:32:50 +0100823 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
824 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100825 }
826
827 // If the contents includes any java_sdk_library modules then add them to the stubs.
828 for _, module := range contents {
829 if _, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100830 // Add information for every possible API scope needed by hidden API.
831 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
832 addFromModule(ctx, module, apiScope)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100833 }
834 }
835 }
836
Paul Duffind061d402021-06-07 21:36:01 +0100837 ctx.VisitDirectDeps(func(module android.Module) {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100838 tag := ctx.OtherModuleDependencyTag(module)
839 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100840 apiScope := hiddenAPIStubsTag.apiScope
Paul Duffin5cca7c42021-05-26 10:16:01 +0100841 if hiddenAPIStubsTag.fromAdditionalDependency {
842 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind)
843 if dexJar != nil {
Paul Duffin280a31a2021-06-27 20:28:29 +0100844 i.AdditionalStubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
Paul Duffin5cca7c42021-05-26 10:16:01 +0100845 }
846 } else {
847 addFromModule(ctx, module, apiScope)
848 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100849 }
850 })
851
852 // Normalize the paths, i.e. remove duplicates and sort.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100853 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100854}
855
Paul Duffin280a31a2021-06-27 20:28:29 +0100856func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule {
Paul Duffin31fad802021-06-18 18:14:25 +0100857 transitive := i.DependencyStubDexJarsByScope
Paul Duffin280a31a2021-06-27 20:28:29 +0100858 transitive.addStubDexJarsByModule(i.StubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100859 return transitive
860}
861
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100862// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
863// bootclasspath_fragment module.
864type HiddenAPIFlagOutput struct {
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100865 // The path to the generated annotation-flags.csv file.
866 AnnotationFlagsPath android.Path
867
868 // The path to the generated metadata.csv file.
869 MetadataPath android.Path
870
871 // The path to the generated index.csv file.
872 IndexPath android.Path
873
Paul Duffin191be3a2021-08-10 16:14:16 +0100874 // The path to the generated stub-flags.csv file.
875 StubFlagsPath android.Path
876
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100877 // The path to the generated all-flags.csv file.
878 AllFlagsPath android.Path
Paul Duffin67b9d612021-07-21 17:38:47 +0100879
880 // The path to the generated signature-patterns.txt file which defines the subset of the
881 // monolithic hidden API files provided in this.
882 SignaturePatternsPath android.Path
Paul Duffin191be3a2021-08-10 16:14:16 +0100883
884 // The path to the generated filtered-stub-flags.csv file.
885 FilteredStubFlagsPath android.Path
886
887 // The path to the generated filtered-flags.csv file.
888 FilteredFlagsPath android.Path
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100889}
890
Paul Duffin5f148ca2021-06-02 17:24:22 +0100891// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
892// path.
893type bootDexJarByModule map[string]android.Path
894
895// addPath adds the path for a module to the map.
896func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
897 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
898}
899
Paul Duffine5218812021-06-07 13:28:19 +0100900// bootDexJars returns the boot dex jar paths sorted by their keys.
901func (b bootDexJarByModule) bootDexJars() android.Paths {
902 paths := android.Paths{}
903 for _, k := range android.SortedStringKeys(b) {
904 paths = append(paths, b[k])
905 }
906 return paths
907}
908
Paul Duffin7f872162021-06-17 19:33:24 +0100909// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
910// libraries if present.
911func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
912 paths := android.Paths{}
913 for _, k := range android.SortedStringKeys(b) {
914 if k == "jacocoagent" {
915 continue
916 }
917 paths = append(paths, b[k])
918 }
919 return paths
920}
921
Paul Duffine5218812021-06-07 13:28:19 +0100922// HiddenAPIOutput encapsulates the output from the hidden API processing.
923type HiddenAPIOutput struct {
924 HiddenAPIFlagOutput
925
926 // The map from base module name to the path to the encoded boot dex file.
927 EncodedBootDexFilesByModule bootDexJarByModule
928}
929
Paul Duffindfa10832021-05-13 17:31:51 +0100930// pathForValidation creates a path of the same type as the supplied type but with a name of
931// <path>.valid.
932//
933// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
934// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
935func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
936 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
937 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
938}
939
Paul Duffin2fef1362021-04-15 13:32:00 +0100940// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
941// the flags from all the modules, the stub flags, augmented with some additional configuration
942// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100943//
944// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
945// an entry for every single member in the dex implementation jars of the individual modules. Every
946// signature in any of the other files MUST be included in this file.
947//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100948// annotationFlags is the path to the annotation flags file generated from annotation information
949// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100950//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100951// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100952// the annotationFlags.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100953func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
Paul Duffind061d402021-06-07 21:36:01 +0100954 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
Paul Duffin67b9d612021-07-21 17:38:47 +0100955 flagFilesByCategory FlagFilesByCategory, flagSubsets SignatureCsvSubsets, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100956
Paul Duffindfa10832021-05-13 17:31:51 +0100957 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100958 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100959 rule := android.NewRuleBuilder(pctx, ctx)
960 command := rule.Command().
961 BuiltTool("generate_hiddenapi_lists").
962 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffind061d402021-06-07 21:36:01 +0100963 Inputs(annotationFlagPaths).
Paul Duffin702210b2021-04-08 20:12:41 +0100964 FlagWithOutput("--output ", tempPath)
965
Paul Duffine3dc6602021-04-14 09:50:43 +0100966 // Add the options for the different categories of flag files.
Paul Duffin524c82c2021-06-09 14:39:28 +0100967 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100968 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100969 for _, path := range paths {
970 category.commandMutator(command, path)
971 }
Paul Duffin702210b2021-04-08 20:12:41 +0100972 }
973
Paul Duffin32cf58a2021-05-18 16:32:50 +0100974 // If available then pass the automatically generated file containing dex signatures of removed
975 // API members to the rule so they can be marked as removed.
976 if generatedRemovedDexSignatures.Valid() {
977 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
978 }
979
Paul Duffin702210b2021-04-08 20:12:41 +0100980 commitChangeForRestat(rule, tempPath, outputPath)
981
Paul Duffin2e880972021-06-23 23:29:09 +0100982 // If there are flag files that have been generated by fragments on which this depends then use
983 // them to validate the flag file generated by the rules created by this method.
Paul Duffin67b9d612021-07-21 17:38:47 +0100984 if len(flagSubsets) > 0 {
Paul Duffinbd88c882022-04-07 23:32:19 +0100985 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets,
986 HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
Paul Duffin2e880972021-06-23 23:29:09 +0100987
Paul Duffindfa10832021-05-13 17:31:51 +0100988 // Add the file that indicates that the file generated by this is valid.
989 //
990 // This will cause the validation rule above to be run any time that the output of this rule
991 // changes but the validation will run in parallel with other rules that depend on this file.
992 command.Validation(validFile)
993 }
994
Paul Duffin2fef1362021-04-15 13:32:00 +0100995 rule.Build(name, desc)
996}
997
Paul Duffin67b9d612021-07-21 17:38:47 +0100998// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
999// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
1000type SignatureCsvSubset struct {
1001 // The path to the CSV file containing hidden API flags.
1002 //
1003 // It has the dex member signature as the first column, with flags, one per column, in the
1004 // subsequent columns.
1005 CsvFile android.Path
1006
1007 // The path to the CSV file containing the signature patterns.
1008 //
1009 // It is a single column CSV file with the column containing a signature pattern.
1010 SignaturePatternsFile android.Path
1011}
1012
1013type SignatureCsvSubsets []SignatureCsvSubset
1014
1015func (s SignatureCsvSubsets) RelativeToTop() []string {
1016 result := []string{}
1017 for _, subset := range s {
1018 result = append(result, fmt.Sprintf("%s:%s", subset.CsvFile.RelativeToTop(), subset.SignaturePatternsFile.RelativeToTop()))
1019 }
1020 return result
1021}
1022
1023// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
1024// patterns that will select a subset of the monolithic flags.
Paul Duffin846beb72022-03-15 17:45:57 +00001025func buildRuleSignaturePatternsFile(
1026 ctx android.ModuleContext, flagsPath android.Path,
1027 splitPackages []string, packagePrefixes []string, singlePackages []string) android.Path {
Paul Duffin67b9d612021-07-21 17:38:47 +01001028 patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
1029 // Create a rule to validate the output from the following rule.
1030 rule := android.NewRuleBuilder(pctx, ctx)
Paul Duffin1e18e982021-08-03 15:42:27 +01001031
1032 // Quote any * in the packages to avoid them being expanded by the shell.
1033 quotedSplitPackages := []string{}
1034 for _, pkg := range splitPackages {
1035 quotedSplitPackages = append(quotedSplitPackages, strings.ReplaceAll(pkg, "*", "\\*"))
1036 }
1037
Paul Duffin67b9d612021-07-21 17:38:47 +01001038 rule.Command().
1039 BuiltTool("signature_patterns").
1040 FlagWithInput("--flags ", flagsPath).
Paul Duffin1e18e982021-08-03 15:42:27 +01001041 FlagForEachArg("--split-package ", quotedSplitPackages).
1042 FlagForEachArg("--package-prefix ", packagePrefixes).
Paul Duffin846beb72022-03-15 17:45:57 +00001043 FlagForEachArg("--single-package ", singlePackages).
Paul Duffin67b9d612021-07-21 17:38:47 +01001044 FlagWithOutput("--output ", patternsFile)
1045 rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
1046
1047 return patternsFile
1048}
1049
Paul Duffinbd88c882022-04-07 23:32:19 +01001050// buildRuleRemoveSignaturesWithImplementationFlags creates a rule that will remove signatures from
1051// the input flags file which have only the implementation flags, i.e. are not part of an API.
1052//
1053// The implementationFlags specifies the set of default flags that identifies the signature of a
1054// private, implementation only, member. Signatures that match those flags are removed from the
1055// flags as they are implementation only.
1056//
1057// This is used to remove implementation only signatures from the signature files that are persisted
1058// in the sdk snapshot as the sdk snapshots should not include implementation details. The
1059// signatures generated by this method will be compared by the buildRuleValidateOverlappingCsvFiles
1060// method which treats any missing signatures as if they were implementation only signatures.
1061func buildRuleRemoveSignaturesWithImplementationFlags(ctx android.BuilderContext,
1062 name string, desc string, inputPath android.Path, filteredPath android.WritablePath,
1063 implementationFlags []string) {
1064
Paul Duffin280bae62021-07-20 18:03:53 +01001065 rule := android.NewRuleBuilder(pctx, ctx)
Paul Duffinbd88c882022-04-07 23:32:19 +01001066 implementationFlagPattern := ""
1067 for _, implementationFlag := range implementationFlags {
1068 implementationFlagPattern = implementationFlagPattern + "," + implementationFlag
1069 }
Paul Duffin280bae62021-07-20 18:03:53 +01001070 rule.Command().
Paul Duffinbd88c882022-04-07 23:32:19 +01001071 Text(`grep -vE "^[^,]+` + implementationFlagPattern + `$"`).Input(inputPath).
1072 Text(">").Output(filteredPath).
Paul Duffin280bae62021-07-20 18:03:53 +01001073 // Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
1074 // something and 1 (build failure) when it does not and 2 (when it encounters an error).
1075 // However, while it is unlikely it is not an error if this does not find any matches. The
1076 // following will only run if the grep does not find something and in that case it will treat
1077 // an exit code of 1 as success and anything else as failure.
1078 Text("|| test $? -eq 1")
1079 rule.Build(name, desc)
1080}
1081
Paul Duffin2e880972021-06-23 23:29:09 +01001082// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
1083// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
Paul Duffinbd88c882022-04-07 23:32:19 +01001084//
1085// The implementationFlags specifies the set of default flags that identifies the signature of a
1086// private, implementation only, member. A signature which is present in a monolithic flags subset
1087// defined by SignatureCsvSubset but which is not present in the flags file from the corresponding
1088// module is assumed to be an implementation only member and so must have these flags.
1089func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string,
1090 monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets,
1091 implementationFlags []string) android.WritablePath {
Paul Duffin2e880972021-06-23 23:29:09 +01001092 // The file which is used to record that the flags file is valid.
1093 validFile := pathForValidation(ctx, monolithicFilePath)
1094
1095 // Create a rule to validate the output from the following rule.
1096 rule := android.NewRuleBuilder(pctx, ctx)
Paul Duffin67b9d612021-07-21 17:38:47 +01001097 command := rule.Command().
Paul Duffin2e880972021-06-23 23:29:09 +01001098 BuiltTool("verify_overlaps").
Paul Duffin0c12b782022-04-08 00:28:11 +01001099 FlagWithInput("--monolithic-flags ", monolithicFilePath)
Paul Duffin67b9d612021-07-21 17:38:47 +01001100
1101 for _, subset := range csvSubsets {
1102 command.
Paul Duffin0c12b782022-04-08 00:28:11 +01001103 Flag("--module-flags ").
Paul Duffin67b9d612021-07-21 17:38:47 +01001104 Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile).
1105 Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile)
1106 }
1107
Paul Duffinbd88c882022-04-07 23:32:19 +01001108 for _, implementationFlag := range implementationFlags {
1109 command.FlagWithArg("--implementation-flag ", implementationFlag)
1110 }
1111
Paul Duffin67b9d612021-07-21 17:38:47 +01001112 // If validation passes then update the file that records that.
1113 command.Text("&& touch").Output(validFile)
Paul Duffin2e880972021-06-23 23:29:09 +01001114 rule.Build(name+"Validation", desc+" validation")
1115
1116 return validFile
1117}
1118
Paul Duffinaf705182022-09-14 11:47:34 +01001119// hiddenAPIFlagRulesForBootclasspathFragment will generate all the flags for a fragment of the
1120// bootclasspath.
Paul Duffin2fef1362021-04-15 13:32:00 +01001121//
1122// It takes:
1123// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
1124// * The list of modules that are the contents of the fragment.
1125// * The additional manually curated flag files to use.
1126//
1127// It generates:
1128// * stub-flags.csv
1129// * annotation-flags.csv
1130// * metadata.csv
1131// * index.csv
1132// * all-flags.csv
Paul Duffinaf705182022-09-14 11:47:34 +01001133func hiddenAPIFlagRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, contents []android.Module, input HiddenAPIFlagInput) HiddenAPIFlagOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +01001134 hiddenApiSubDir := "modular-hiddenapi"
1135
Paul Duffin1352f7c2021-05-21 22:18:49 +01001136 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +01001137 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffin2e880972021-06-23 23:29:09 +01001138 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
Paul Duffin2fef1362021-04-15 13:32:00 +01001139
Paul Duffin537ea3d2021-05-14 10:38:00 +01001140 // Extract the classes jars from the contents.
Paul Duffindd5993f2021-06-10 10:18:22 +01001141 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001142
Paul Duffin2fef1362021-04-15 13:32:00 +01001143 // Generate the set of flags from the annotations in the source code.
1144 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001145 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001146
1147 // Generate the metadata from the annotations in the source code.
1148 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001149 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001150
Paul Duffin537ea3d2021-05-14 10:38:00 +01001151 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +01001152 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001153 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001154
Paul Duffinaf99afa2021-05-21 22:18:56 +01001155 // 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 +01001156 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
1157 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin32cf58a2021-05-18 16:32:50 +01001158 // signatures, see the combined-removed-dex module. This does that automatically by using the
1159 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
1160 // stub_libs and contents properties of a bootclasspath_fragment.
1161 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +01001162
1163 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
1164 // files.
Paul Duffine5218812021-06-07 13:28:19 +01001165 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
Paul Duffind061d402021-06-07 21:36:01 +01001166 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
Paul Duffine5218812021-06-07 13:28:19 +01001167
Paul Duffin280bae62021-07-20 18:03:53 +01001168 // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
1169 // compared against the monolithic stub flags.
1170 filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
Paul Duffinbd88c882022-04-07 23:32:19 +01001171 buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredStubFlags",
1172 "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV,
1173 HIDDENAPI_STUB_FLAGS_IMPL_FLAGS)
Paul Duffin280bae62021-07-20 18:03:53 +01001174
1175 // Generate the filtered-flags.csv file which contains the filtered flags that will be compared
1176 // against the monolithic flags.
1177 filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
Paul Duffinbd88c882022-04-07 23:32:19 +01001178 buildRuleRemoveSignaturesWithImplementationFlags(ctx, "modularHiddenApiFilteredFlags",
1179 "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV,
1180 HIDDENAPI_FLAGS_CSV_IMPL_FLAGS)
Paul Duffin280bae62021-07-20 18:03:53 +01001181
Paul Duffin2fef1362021-04-15 13:32:00 +01001182 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffinaf705182022-09-14 11:47:34 +01001183 return HiddenAPIFlagOutput{
1184 AnnotationFlagsPath: annotationFlagsCSV,
1185 MetadataPath: metadataCSV,
1186 IndexPath: indexCSV,
1187 StubFlagsPath: stubFlagsCSV,
1188 AllFlagsPath: allFlagsCSV,
1189 FilteredStubFlagsPath: filteredStubFlagsCSV,
1190 FilteredFlagsPath: filteredFlagsCSV,
Paul Duffin1e6f5c42021-05-21 16:15:31 +01001191 }
Paul Duffinaf705182022-09-14 11:47:34 +01001192}
1193
1194// hiddenAPIEncodeRulesForBootclasspathFragment generates rules to encode hidden API flags into the
1195// dex jars in bootDexInfoByModule.
1196func hiddenAPIEncodeRulesForBootclasspathFragment(ctx android.ModuleContext, bootDexInfoByModule bootDexInfoByModule, allFlagsCSV android.Path) bootDexJarByModule {
1197 // Encode the flags into the boot dex files.
1198 encodedBootDexJarsByModule := bootDexJarByModule{}
1199 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
1200 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
1201 bootDexInfo := bootDexInfoByModule[name]
1202 unencodedDex := bootDexInfo.path
1203 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, bootDexInfo.minSdkVersion, outputDir)
1204 encodedBootDexJarsByModule[name] = encodedDex
1205 }
1206 return encodedBootDexJarsByModule
Paul Duffin702210b2021-04-08 20:12:41 +01001207}
Paul Duffin537ea3d2021-05-14 10:38:00 +01001208
Paul Duffin32cf58a2021-05-18 16:32:50 +01001209func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
1210 if len(removedTxtFiles) == 0 {
1211 return android.OptionalPath{}
1212 }
1213
1214 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
1215
1216 rule := android.NewRuleBuilder(pctx, ctx)
1217 rule.Command().
1218 BuiltTool("metalava").
1219 Flag("--no-banner").
1220 Inputs(removedTxtFiles).
1221 FlagWithOutput("--dex-api ", output)
1222 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
1223 return android.OptionalPathForPath(output)
1224}
1225
Paul Duffindd5993f2021-06-10 10:18:22 +01001226// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffine5218812021-06-07 13:28:19 +01001227func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1228 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +01001229 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +01001230 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
1231 if hiddenAPIModule == nil {
1232 continue
1233 }
Paul Duffine5218812021-06-07 13:28:19 +01001234 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
1235 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001236 }
1237 return bootDexJars
1238}
1239
Paul Duffindd5993f2021-06-10 10:18:22 +01001240func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
1241 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
1242 return hiddenAPIModule
1243 } else if _, ok := module.(*DexImport); ok {
1244 // Ignore this for the purposes of hidden API processing
1245 } else {
1246 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
1247 }
1248
1249 return nil
1250}
1251
Paul Duffine5218812021-06-07 13:28:19 +01001252// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
1253type bootDexInfo struct {
1254 // The path to the dex jar that has not had hidden API flags encoded into it.
1255 path android.Path
1256
1257 // Indicates whether the dex jar needs uncompressing before encoding.
1258 uncompressDex bool
Paul Duffin09817d62022-04-28 17:45:11 +01001259
1260 // The minimum sdk version that the dex jar will be used on.
1261 minSdkVersion android.SdkSpec
Paul Duffine5218812021-06-07 13:28:19 +01001262}
1263
1264// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
1265// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
1266type bootDexInfoByModule map[string]bootDexInfo
1267
1268// bootDexJars returns the boot dex jar paths sorted by their keys.
1269func (b bootDexInfoByModule) bootDexJars() android.Paths {
1270 paths := android.Paths{}
1271 for _, m := range android.SortedStringKeys(b) {
1272 paths = append(paths, b[m].path)
1273 }
1274 return paths
1275}
1276
1277// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
1278// each of the supplied modules which must implement hiddenAPIModule.
1279func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
1280 bootDexJarsByModule := bootDexInfoByModule{}
1281 for _, module := range contents {
1282 hiddenAPIModule := module.(hiddenAPIModule)
1283 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
1284 bootDexJarsByModule[module.Name()] = bootDexInfo{
1285 path: bootDexJar,
1286 uncompressDex: *hiddenAPIModule.uncompressDex(),
Paul Duffin09817d62022-04-28 17:45:11 +01001287 minSdkVersion: hiddenAPIModule.MinSdkVersion(ctx),
Paul Duffine5218812021-06-07 13:28:19 +01001288 }
1289 }
1290
1291 return bootDexJarsByModule
1292}
1293
1294// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
1295//
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001296// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is unset or
1297// invalid, then create a fake path and either report an error immediately or defer reporting of the
1298// error until the path is actually used.
Paul Duffine5218812021-06-07 13:28:19 +01001299func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
1300 bootDexJar := module.bootDexJar()
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001301 if !bootDexJar.Valid() {
Paul Duffine5218812021-06-07 13:28:19 +01001302 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001303 handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
1304 return fake
Paul Duffine5218812021-06-07 13:28:19 +01001305 }
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001306 return bootDexJar.Path()
Paul Duffine5218812021-06-07 13:28:19 +01001307}
1308
Paul Duffindd5993f2021-06-10 10:18:22 +01001309// extractClassesJarsFromModules extracts the class jars from the supplied modules.
1310func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +01001311 classesJars := android.Paths{}
1312 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +01001313 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001314 }
1315 return classesJars
1316}
Paul Duffin5f148ca2021-06-02 17:24:22 +01001317
Paul Duffindd5993f2021-06-10 10:18:22 +01001318// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
1319func retrieveClassesJarsFromModule(module android.Module) android.Paths {
1320 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
1321 return hiddenAPIModule.classesJars()
1322 }
1323
1324 return nil
1325}
1326
Paul Duffin5f148ca2021-06-02 17:24:22 +01001327// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
1328// Soong but should instead only be reported in ninja if the file is actually built.
1329func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
Paul Duffine5218812021-06-07 13:28:19 +01001330 // Any missing dependency should be allowed.
1331 if ctx.Config().AllowMissingDependencies() {
1332 return true
1333 }
1334
Paul Duffinef083c92021-06-29 13:36:34 +01001335 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
1336 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
1337 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
1338 // failures missing boot dex jars need to be deferred.
1339 if android.IsModuleInVersionedSdk(ctx.Module()) {
1340 return true
1341 }
1342
Paul Duffin5f148ca2021-06-02 17:24:22 +01001343 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
1344 //
1345 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
1346 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
1347 // but unfortunately, due to b/187910671 it does.
1348 //
1349 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
1350 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
1351 // has an APEX variant not a platform variant.
1352 //
1353 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
1354 // provide a boot dex jar:
1355 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
1356 // does not have an APEX variant and only has a platform variant and neither do its content
1357 // modules.
1358 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
1359 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
1360 // of an apex they cannot provide a boot dex jar.
1361 //
1362 // The first case causes problems when the affected prebuilt modules are preferred but that is an
1363 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
1364 // complete. The second case is used for building targets that do not use boot dex jars and so
1365 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
1366 // That is handled above.
1367 //
1368 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
1369 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
1370 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
1371 // that if the library can be part of an APEX then it is the APEX variant that is used.
1372 //
1373 // This check handles the slightly different requirements of the bootclasspath_fragment and
1374 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
1375 // a prebuilt modules that has other variants which are part of an APEX.
1376 //
1377 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
1378 if android.IsModulePrebuilt(module) {
Paul Duffinef083c92021-06-29 13:36:34 +01001379 // An inactive source module can still contribute to the APEX but an inactive prebuilt module
1380 // should not contribute to anything. So, rather than have a missing dex jar cause a Soong
1381 // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly
1382 // built Ninja should never use the dex jar file.
1383 if !isActiveModule(module) {
1384 return true
1385 }
1386
Paul Duffin5f148ca2021-06-02 17:24:22 +01001387 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
1388 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
1389 if apexInfo.IsForPlatform() {
1390 return true
1391 }
1392 }
1393 }
1394
Paul Duffin5f148ca2021-06-02 17:24:22 +01001395 return false
1396}
1397
1398// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
1399// file depending on the value returned from deferReportingMissingBootDexJar.
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001400func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath, reason string) {
Paul Duffin5f148ca2021-06-02 17:24:22 +01001401 if deferReportingMissingBootDexJar(ctx, module) {
1402 // Create an error rule that pretends to create the output file but will actually fail if it
1403 // is run.
1404 ctx.Build(pctx, android.BuildParams{
1405 Rule: android.ErrorRule,
1406 Output: fake,
1407 Args: map[string]string{
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001408 "error": fmt.Sprintf("missing boot dex jar dependency for %s: %s", module, reason),
Paul Duffin5f148ca2021-06-02 17:24:22 +01001409 },
1410 })
1411 } else {
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001412 ctx.ModuleErrorf("module %s does not provide a dex jar: %s", module, reason)
Paul Duffin5f148ca2021-06-02 17:24:22 +01001413 }
1414}
1415
1416// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
1417// DexJarBuildPath() method.
1418//
1419// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
1420// However, under certain conditions, e.g. errors, or special build configurations it will return
1421// a path to a fake file.
1422func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001423 bootDexJar := module.(interface{ DexJarBuildPath() OptionalDexJarPath }).DexJarBuildPath()
1424 if !bootDexJar.Valid() {
Paul Duffin5f148ca2021-06-02 17:24:22 +01001425 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001426 handleMissingDexBootFile(ctx, module, fake, bootDexJar.InvalidReason())
1427 return fake
Paul Duffin5f148ca2021-06-02 17:24:22 +01001428 }
Martin Stjernholm8be1e6d2021-09-15 03:34:04 +01001429 return bootDexJar.Path()
Paul Duffin5f148ca2021-06-02 17:24:22 +01001430}
1431
1432// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
1433func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1434 encodedDexJarsByModuleName := bootDexJarByModule{}
1435 for _, module := range contents {
1436 path := retrieveEncodedBootDexJarFromModule(ctx, module)
1437 encodedDexJarsByModuleName.addPath(module, path)
1438 }
1439 return encodedDexJarsByModuleName
1440}