blob: 8e39f408e5e0161644355670ddf1c25e8cbf29d2 [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 Duffinc6bb7cf2021-04-08 17:49:27 +010023)
24
25// Contains support for processing hiddenAPI in a modular fashion.
26
Paul Duffin31fad802021-06-18 18:14:25 +010027// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API
28// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do
29// not provide the information needed by hidden API processing.
30type HiddenAPIScope struct {
31 // The name of the scope, used for debug purposes.
32 name string
33
34 // The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules.
35 sdkKind android.SdkKind
36
37 // The option needed to passed to "hiddenapi list".
38 hiddenAPIListOption string
Paul Duffin5cca7c42021-05-26 10:16:01 +010039
40 // The name sof the source stub library modules that contain the API provided by the platform,
41 // i.e. by modules that are not in an APEX.
42 nonUpdatableSourceModule string
43
44 // The names of the prebuilt stub library modules that contain the API provided by the platform,
45 // i.e. by modules that are not in an APEX.
46 nonUpdatablePrebuiltModule string
Paul Duffin31fad802021-06-18 18:14:25 +010047}
48
49// initHiddenAPIScope initializes the scope.
50func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
Paul Duffin5cca7c42021-05-26 10:16:01 +010051 sdkKind := apiScope.sdkKind
52 // The platform does not provide a core platform API.
53 if sdkKind != android.SdkCorePlatform {
54 kindAsString := sdkKind.String()
55 var insert string
56 if sdkKind == android.SdkPublic {
57 insert = ""
58 } else {
59 insert = "." + strings.ReplaceAll(kindAsString, "-", "_")
60 }
61
62 nonUpdatableModule := "android-non-updatable"
63
64 // Construct the name of the android-non-updatable source module for this scope.
65 apiScope.nonUpdatableSourceModule = fmt.Sprintf("%s.stubs%s", nonUpdatableModule, insert)
66
67 prebuiltModuleName := func(name string, kind string) string {
68 return fmt.Sprintf("sdk_%s_current_%s", kind, name)
69 }
70
71 // Construct the name of the android-non-updatable prebuilt module for this scope.
72 apiScope.nonUpdatablePrebuiltModule = prebuiltModuleName(nonUpdatableModule, kindAsString)
73 }
74
Paul Duffin31fad802021-06-18 18:14:25 +010075 return apiScope
76}
77
Paul Duffin5cca7c42021-05-26 10:16:01 +010078// android-non-updatable takes the name of a module and returns a possibly scope specific name of
79// the module.
80func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext, name string) string {
81 // The android-non-updatable is not a java_sdk_library but there are separate stub libraries for
82 // each scope.
83 // TODO(b/192067200): Remove special handling of android-non-updatable.
84 if name == "android-non-updatable" {
85 if ctx.Config().AlwaysUsePrebuiltSdks() {
86 return l.nonUpdatablePrebuiltModule
87 } else {
88 return l.nonUpdatableSourceModule
89 }
90 } else {
91 // Assume that the module is either a java_sdk_library (or equivalent) and so will provide
92 // separate stub jars for each scope or is a java_library (or equivalent) in which case it will
93 // have the same stub jar for each scope.
94 return name
95 }
96}
97
Paul Duffin31fad802021-06-18 18:14:25 +010098func (l *HiddenAPIScope) String() string {
99 return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
100}
101
102var (
103 PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
104 name: "public",
105 sdkKind: android.SdkPublic,
106 hiddenAPIListOption: "--public-stub-classpath",
107 })
108 SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
109 name: "system",
110 sdkKind: android.SdkSystem,
111 hiddenAPIListOption: "--system-stub-classpath",
112 })
113 TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
114 name: "test",
115 sdkKind: android.SdkTest,
116 hiddenAPIListOption: "--test-stub-classpath",
117 })
Paul Duffinb51db2e2021-06-21 14:08:08 +0100118 ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
119 name: "module-lib",
120 sdkKind: android.SdkModule,
121 })
Paul Duffin31fad802021-06-18 18:14:25 +0100122 CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
123 name: "core-platform",
124 sdkKind: android.SdkCorePlatform,
125 hiddenAPIListOption: "--core-platform-stub-classpath",
126 })
127
128 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
129 // API processing.
130 //
131 // These are roughly in order from narrowest API surface to widest. Widest means the API stubs
132 // with the biggest API surface, e.g. test is wider than system is wider than public.
133 //
Paul Duffinb51db2e2021-06-21 14:08:08 +0100134 // Core platform is considered wider than system/module-lib because those modules that provide
135 // core platform APIs either do not have any system/module-lib APIs at all, or if they do it is
136 // because the core platform API is being converted to system/module-lib APIs. In either case the
137 // system/module-lib APIs are subsets of the core platform API.
Paul Duffin31fad802021-06-18 18:14:25 +0100138 //
139 // 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 +0100140 // is neither wider or narrower than the module-lib or core platform APIs. However, this works
141 // well enough at the moment.
Paul Duffin31fad802021-06-18 18:14:25 +0100142 // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
143 hiddenAPIScopes = []*HiddenAPIScope{
144 PublicHiddenAPIScope,
145 SystemHiddenAPIScope,
146 TestHiddenAPIScope,
Paul Duffinb51db2e2021-06-21 14:08:08 +0100147 ModuleLibHiddenAPIScope,
Paul Duffin31fad802021-06-18 18:14:25 +0100148 CorePlatformHiddenAPIScope,
149 }
150
151 // The HiddenAPIScope instances that are supported by a java_sdk_library.
152 //
153 // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
154 // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
155 hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{
156 PublicHiddenAPIScope,
157 SystemHiddenAPIScope,
158 TestHiddenAPIScope,
Paul Duffinb51db2e2021-06-21 14:08:08 +0100159 ModuleLibHiddenAPIScope,
Paul Duffin31fad802021-06-18 18:14:25 +0100160 }
161
162 // The HiddenAPIScope instances that are supported by the `hiddenapi list`.
163 hiddenAPIFlagScopes = []*HiddenAPIScope{
164 PublicHiddenAPIScope,
165 SystemHiddenAPIScope,
166 TestHiddenAPIScope,
167 CorePlatformHiddenAPIScope,
168 }
169)
170
Paul Duffin74431d52021-04-21 14:10:42 +0100171type hiddenAPIStubsDependencyTag struct {
172 blueprint.BaseDependencyTag
Paul Duffin31fad802021-06-18 18:14:25 +0100173
174 // The api scope for which this dependency was added.
175 apiScope *HiddenAPIScope
Paul Duffin5cca7c42021-05-26 10:16:01 +0100176
177 // Indicates that the dependency is not for an API provided by the current bootclasspath fragment
178 // but is an additional API provided by a module that is not part of the current bootclasspath
179 // fragment.
180 fromAdditionalDependency bool
Paul Duffin74431d52021-04-21 14:10:42 +0100181}
182
183func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
184}
185
186func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool {
187 return false
188}
189
Paul Duffin976b0e52021-04-27 23:20:26 +0100190func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100191 // Do not add additional dependencies to the sdk.
192 if b.fromAdditionalDependency {
193 return nil
194 }
195
Paul Duffin976b0e52021-04-27 23:20:26 +0100196 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
197 // property, otherwise treat if it was specified in the java_header_libs property.
198 if javaSdkLibrarySdkMemberType.IsInstance(child) {
199 return javaSdkLibrarySdkMemberType
200 }
201
202 return javaHeaderLibsSdkMemberType
203}
204
205func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
206 // Export the module added via this dependency tag from the sdk.
207 return true
208}
209
Paul Duffin74431d52021-04-21 14:10:42 +0100210// Avoid having to make stubs content explicitly visible to dependent modules.
211//
212// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
213// with proper dependencies.
214// TODO(b/177892522): Remove this and add needed visibility.
215func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
216}
217
218var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
219var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
220var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
Paul Duffin976b0e52021-04-27 23:20:26 +0100221var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
Paul Duffin74431d52021-04-21 14:10:42 +0100222
Paul Duffin74431d52021-04-21 14:10:42 +0100223// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
224// needed to produce the hidden API monolithic stub flags file.
Paul Duffin31fad802021-06-18 18:14:25 +0100225func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string {
Paul Duffin74431d52021-04-21 14:10:42 +0100226 var publicStubModules []string
227 var systemStubModules []string
228 var testStubModules []string
229 var corePlatformStubModules []string
230
231 if config.AlwaysUsePrebuiltSdks() {
232 // Build configuration mandates using prebuilt stub modules
233 publicStubModules = append(publicStubModules, "sdk_public_current_android")
234 systemStubModules = append(systemStubModules, "sdk_system_current_android")
235 testStubModules = append(testStubModules, "sdk_test_current_android")
236 } else {
237 // Use stub modules built from source
238 publicStubModules = append(publicStubModules, "android_stubs_current")
239 systemStubModules = append(systemStubModules, "android_system_stubs_current")
240 testStubModules = append(testStubModules, "android_test_stubs_current")
241 }
242 // We do not have prebuilts of the core platform api yet
243 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
244
245 // Allow products to define their own stubs for custom product jars that apps can use.
246 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
247 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
248 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
249 if config.IsEnvTrue("EMMA_INSTRUMENT") {
Paul Duffin098c8782021-05-14 10:45:25 +0100250 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
251 // allows everyone access but it is needed to ensure consistent flags between the
252 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
Paul Duffin74431d52021-04-21 14:10:42 +0100253 publicStubModules = append(publicStubModules, "jacoco-stubs")
Paul Duffin098c8782021-05-14 10:45:25 +0100254 systemStubModules = append(systemStubModules, "jacoco-stubs")
255 testStubModules = append(testStubModules, "jacoco-stubs")
Paul Duffin74431d52021-04-21 14:10:42 +0100256 }
257
Paul Duffin31fad802021-06-18 18:14:25 +0100258 m := map[*HiddenAPIScope][]string{}
259 m[PublicHiddenAPIScope] = publicStubModules
260 m[SystemHiddenAPIScope] = systemStubModules
261 m[TestHiddenAPIScope] = testStubModules
262 m[CorePlatformHiddenAPIScope] = corePlatformStubModules
Paul Duffin74431d52021-04-21 14:10:42 +0100263 return m
264}
265
266// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
Paul Duffin31fad802021-06-18 18:14:25 +0100267// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
268// tag to identify the source of the dependency.
269func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) {
Paul Duffin74431d52021-04-21 14:10:42 +0100270 module := ctx.Module()
Paul Duffin31fad802021-06-18 18:14:25 +0100271 for _, apiScope := range hiddenAPIScopes {
272 modules := apiScopeToStubLibModules[apiScope]
273 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...)
Paul Duffin74431d52021-04-21 14:10:42 +0100274 }
275}
276
Paul Duffin74431d52021-04-21 14:10:42 +0100277// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
278// available, or reports an error.
Paul Duffin10931582021-04-25 10:13:54 +0100279func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
280 var dexJar android.Path
281 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
282 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
283 } else if j, ok := module.(UsesLibraryDependency); ok {
284 dexJar = j.DexJarBuildPath()
Paul Duffin74431d52021-04-21 14:10:42 +0100285 } else {
286 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 +0100287 return nil
Paul Duffin74431d52021-04-21 14:10:42 +0100288 }
Paul Duffin10931582021-04-25 10:13:54 +0100289
290 if dexJar == nil {
291 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
292 }
293 return dexJar
Paul Duffin74431d52021-04-21 14:10:42 +0100294}
295
Paul Duffin4539a372021-06-23 23:20:43 +0100296// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
Paul Duffin74431d52021-04-21 14:10:42 +0100297//
298// The rule is initialized but not built so that the caller can modify it and select an appropriate
299// name.
Paul Duffin67b9d612021-07-21 17:38:47 +0100300func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, stubFlagSubsets SignatureCsvSubsets) {
Paul Duffin74431d52021-04-21 14:10:42 +0100301 // Singleton rule which applies hiddenapi on all boot class path dex files.
302 rule := android.NewRuleBuilder(pctx, ctx)
303
304 tempPath := tempPathForRestat(ctx, outputPath)
305
Paul Duffinf1b358c2021-05-17 07:38:47 +0100306 // Find the widest API stubs provided by the fragments on which this depends, if any.
Paul Duffind2b1e0c2021-06-27 20:53:39 +0100307 dependencyStubDexJars := input.DependencyStubDexJarsByScope.StubDexJarsForWidestAPIScope()
Paul Duffin5cca7c42021-05-26 10:16:01 +0100308
309 // Add widest API stubs from the additional dependencies of this, if any.
Paul Duffind2b1e0c2021-06-27 20:53:39 +0100310 dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.StubDexJarsForWidestAPIScope()...)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100311
Paul Duffin74431d52021-04-21 14:10:42 +0100312 command := rule.Command().
313 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
314 Text("list").
Paul Duffinf1b358c2021-05-17 07:38:47 +0100315 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100316 FlagForEachInput("--boot-dex=", bootDexJars)
317
Paul Duffin156b5d32021-06-24 23:06:52 +0100318 // If no module stub flags paths are provided then this must be being called for a
319 // bootclasspath_fragment and not the whole platform_bootclasspath.
Paul Duffin67b9d612021-07-21 17:38:47 +0100320 if stubFlagSubsets == nil {
Paul Duffin156b5d32021-06-24 23:06:52 +0100321 // This is being run on a fragment of the bootclasspath.
322 command.Flag("--fragment")
323 }
324
Paul Duffin31fad802021-06-18 18:14:25 +0100325 // Iterate over the api scopes in a fixed order.
326 for _, apiScope := range hiddenAPIFlagScopes {
327 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
328 // They will be needed to resolve dependencies from this fragment's stubs to classes in the
329 // other fragment's APIs.
330 var paths android.Paths
Paul Duffin280a31a2021-06-27 20:28:29 +0100331 paths = append(paths, input.DependencyStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
332 paths = append(paths, input.AdditionalStubDexJarsByScope.StubDexJarsForScope(apiScope)...)
333 paths = append(paths, input.StubDexJarsByScope.StubDexJarsForScope(apiScope)...)
Paul Duffin74431d52021-04-21 14:10:42 +0100334 if len(paths) > 0 {
Paul Duffin31fad802021-06-18 18:14:25 +0100335 option := apiScope.hiddenAPIListOption
336 command.FlagWithInputList(option+"=", paths, ":")
Paul Duffin74431d52021-04-21 14:10:42 +0100337 }
338 }
339
340 // Add the output path.
341 command.FlagWithOutput("--out-api-flags=", tempPath)
342
Paul Duffin2e880972021-06-23 23:29:09 +0100343 // If there are stub flag files that have been generated by fragments on which this depends then
344 // use them to validate the stub flag file generated by the rules created by this method.
Paul Duffin67b9d612021-07-21 17:38:47 +0100345 if len(stubFlagSubsets) > 0 {
346 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, stubFlagSubsets)
Paul Duffin2e880972021-06-23 23:29:09 +0100347
348 // Add the file that indicates that the file generated by this is valid.
349 //
350 // This will cause the validation rule above to be run any time that the output of this rule
351 // changes but the validation will run in parallel with other rules that depend on this file.
352 command.Validation(validFile)
353 }
354
Paul Duffin74431d52021-04-21 14:10:42 +0100355 commitChangeForRestat(rule, tempPath, outputPath)
Paul Duffin4539a372021-06-23 23:20:43 +0100356
357 rule.Build(name, desc)
Paul Duffin74431d52021-04-21 14:10:42 +0100358}
359
Paul Duffin46169772021-04-14 15:01:56 +0100360// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
361// information obtained from annotations within the source code in order to create the complete set
362// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100363//
364// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
365// of each property reference a plain text file that contains a java signature per line. The flags
366// for each of those signatures will be updated in a property specific way.
367//
368// The Unsupported_packages property contains a list of paths, each of which is a plain text file
369// with one Java package per line. All members of all classes within that package (but not nested
370// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100371type HiddenAPIFlagFileProperties struct {
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100372 // Marks each signature in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100373 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100374
375 // Marks each signature in the referenced files as being unsupported because it has been removed.
376 // Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100377 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100378
379 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
380 // and low priority.
Paul Duffin702210b2021-04-08 20:12:41 +0100381 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100382
383 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
Paul Duffin702210b2021-04-08 20:12:41 +0100384 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100385
386 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
Paul Duffin702210b2021-04-08 20:12:41 +0100387 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100388
389 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
390 // and low priority. Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100391 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100392
393 // Marks each signature in the referenced files as being blocked.
Paul Duffin702210b2021-04-08 20:12:41 +0100394 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100395
396 // Marks each signature in every package in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100397 Unsupported_packages []string `android:"path"`
398}
399
Paul Duffine3dc6602021-04-14 09:50:43 +0100400type hiddenAPIFlagFileCategory struct {
Paul Duffin524c82c2021-06-09 14:39:28 +0100401 // PropertyName is the name of the property for this category.
402 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100403
Paul Duffincc17bfe2021-04-19 13:21:20 +0100404 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100405 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100406 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100407
408 // commandMutator adds the appropriate command line options for this category to the supplied
409 // command
410 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
411}
412
Paul Duffin32cf58a2021-05-18 16:32:50 +0100413// The flag file category for removed members of the API.
414//
Paul Duffin524c82c2021-06-09 14:39:28 +0100415// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin32cf58a2021-05-18 16:32:50 +0100416// list of removed API members that are generated automatically from the removed.txt files provided
417// by API stubs.
418var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
419 // See HiddenAPIFlagFileProperties.Removed
Paul Duffin524c82c2021-06-09 14:39:28 +0100420 PropertyName: "removed",
Paul Duffin32cf58a2021-05-18 16:32:50 +0100421 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
422 return properties.Removed
423 },
424 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
425 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
426 },
427}
428
Paul Duffin524c82c2021-06-09 14:39:28 +0100429var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
Paul Duffin46169772021-04-14 15:01:56 +0100430 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100431 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100432 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100433 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100434 return properties.Unsupported
435 },
436 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
437 command.FlagWithInput("--unsupported ", path)
438 },
439 },
Paul Duffin32cf58a2021-05-18 16:32:50 +0100440 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100441 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100442 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100443 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100444 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100445 return properties.Max_target_r_low_priority
446 },
447 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
448 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
449 },
450 },
Paul Duffin46169772021-04-14 15:01:56 +0100451 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100452 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100453 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100454 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100455 return properties.Max_target_q
456 },
457 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
458 command.FlagWithInput("--max-target-q ", path)
459 },
460 },
Paul Duffin46169772021-04-14 15:01:56 +0100461 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100462 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100463 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100464 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100465 return properties.Max_target_p
466 },
467 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
468 command.FlagWithInput("--max-target-p ", path)
469 },
470 },
Paul Duffin46169772021-04-14 15:01:56 +0100471 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100472 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100473 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100474 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100475 return properties.Max_target_o_low_priority
476 },
477 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
478 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
479 },
480 },
Paul Duffin46169772021-04-14 15:01:56 +0100481 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100482 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100483 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100484 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100485 return properties.Blocked
486 },
487 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
488 command.FlagWithInput("--blocked ", path)
489 },
490 },
Paul Duffin46169772021-04-14 15:01:56 +0100491 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100492 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100493 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100494 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100495 return properties.Unsupported_packages
496 },
497 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
498 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
499 },
500 },
Paul Duffin702210b2021-04-08 20:12:41 +0100501}
502
Paul Duffin438eb572021-05-21 16:58:23 +0100503// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
504type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
505
506// append appends the supplied flags files to the corresponding category in this map.
507func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100508 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100509 s[category] = append(s[category], other[category]...)
510 }
511}
512
Paul Duffinaf99afa2021-05-21 22:18:56 +0100513// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100514//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100515// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
516// processing.
517type HiddenAPIInfo struct {
Paul Duffin438eb572021-05-21 16:58:23 +0100518 // FlagFilesByCategory maps from the flag file category to the paths containing information for
519 // that category.
520 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100521
Paul Duffin280a31a2021-06-27 20:28:29 +0100522 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes provided by
523 // this fragment and the fragments on which this depends.
524 TransitiveStubDexJarsByScope StubDexJarsByModule
Paul Duffin18cf1972021-05-21 22:46:59 +0100525
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100526 // The output from the hidden API processing needs to be made available to other modules.
527 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100528}
Paul Duffin702210b2021-04-08 20:12:41 +0100529
Paul Duffinf1b358c2021-05-17 07:38:47 +0100530func newHiddenAPIInfo() *HiddenAPIInfo {
531 info := HiddenAPIInfo{
Paul Duffin31fad802021-06-18 18:14:25 +0100532 FlagFilesByCategory: FlagFilesByCategory{},
Paul Duffin280a31a2021-06-27 20:28:29 +0100533 TransitiveStubDexJarsByScope: StubDexJarsByModule{},
Paul Duffinf1b358c2021-05-17 07:38:47 +0100534 }
535 return &info
536}
537
538func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
539 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
540 // this will introduce duplicates so they will be resolved after processing all the fragments.
541 for _, fragment := range fragments {
542 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
543 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
Paul Duffin280a31a2021-06-27 20:28:29 +0100544 i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100545 }
546 }
Paul Duffinf1b358c2021-05-17 07:38:47 +0100547}
548
Paul Duffin67b9d612021-07-21 17:38:47 +0100549// StubFlagSubset returns a SignatureCsvSubset that contains a path to a stub-flags.csv file and a
550// path to a signature-patterns.csv file that defines a subset of the monolithic stub flags file,
551// i.e. out/soong/hiddenapi/hiddenapi-stub-flags.txt, against which it will be compared.
552func (i *HiddenAPIInfo) StubFlagSubset() SignatureCsvSubset {
553 return SignatureCsvSubset{i.StubFlagsPath, i.SignaturePatternsPath}
554}
555
556// FlagSubset returns a SignatureCsvSubset that contains a path to an all-flags.csv file and a
557// path to a signature-patterns.csv file that defines a subset of the monolithic flags file, i.e.
558// out/soong/hiddenapi/hiddenapi-flags.csv, against which it will be compared.
559func (i *HiddenAPIInfo) FlagSubset() SignatureCsvSubset {
560 return SignatureCsvSubset{i.AllFlagsPath, i.SignaturePatternsPath}
561}
562
Paul Duffinaf99afa2021-05-21 22:18:56 +0100563var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100564
Paul Duffin280a31a2021-06-27 20:28:29 +0100565// ModuleStubDexJars contains the stub dex jars provided by a single module.
566//
567// It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See
568// hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
569type ModuleStubDexJars map[*HiddenAPIScope]android.Path
Paul Duffin1352f7c2021-05-21 22:18:49 +0100570
Paul Duffin280a31a2021-06-27 20:28:29 +0100571// stubDexJarForWidestAPIScope returns the stub dex jars for the widest API scope provided by this
Paul Duffin1352f7c2021-05-21 22:18:49 +0100572// map.
Paul Duffin280a31a2021-06-27 20:28:29 +0100573//
574// The relative width of APIs is determined by their order in hiddenAPIScopes.
575func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100576 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
577 apiScope := hiddenAPIScopes[i]
Paul Duffin280a31a2021-06-27 20:28:29 +0100578 if stubsForAPIScope, ok := s[apiScope]; ok {
Paul Duffin5cca7c42021-05-26 10:16:01 +0100579 return stubsForAPIScope
580 }
581 }
582
583 return nil
584}
585
Paul Duffin280a31a2021-06-27 20:28:29 +0100586// StubDexJarsByModule contains the stub dex jars provided by a set of modules.
587//
588// It maps a module name to the path to the stub dex jars provided by that module.
589type StubDexJarsByModule map[string]ModuleStubDexJars
590
591// addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope.
592func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) {
593 name := android.RemoveOptionalPrebuiltPrefix(module.Name())
Paul Duffin3f0290e2021-06-30 18:25:36 +0100594
595 // Each named module provides one dex jar for each scope. However, in some cases different API
596 // versions of a single classes are provided by separate modules. e.g. the core platform
597 // version of java.lang.Object is provided by the legacy.art.module.platform.api module but the
598 // public version is provided by the art.module.public.api module. In those cases it is necessary
599 // to treat all those modules as they were the same name, otherwise it will result in multiple
600 // definitions of a single class being passed to hidden API processing which will cause an error.
Paul Duffin280a31a2021-06-27 20:28:29 +0100601 if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule {
602 // Treat all *android-non-updatable* modules as if they were part of an android-non-updatable
603 // java_sdk_library.
604 // TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent.
605 name = "android-non-updatable"
606 } else if name == "legacy.art.module.platform.api" {
607 // Treat legacy.art.module.platform.api as if it was an API scope provided by the
608 // art.module.public.api java_sdk_library which will be the case once the former has been
609 // migrated to a module_lib API.
610 name = "art.module.public.api"
611 } else if name == "legacy.i18n.module.platform.api" {
612 // Treat legacy.i18n.module.platform.api as if it was an API scope provided by the
613 // i18n.module.public.api java_sdk_library which will be the case once the former has been
614 // migrated to a module_lib API.
615 name = "i18n.module.public.api"
616 } else if name == "conscrypt.module.platform.api" {
617 // Treat conscrypt.module.platform.api as if it was an API scope provided by the
618 // conscrypt.module.public.api java_sdk_library which will be the case once the former has been
619 // migrated to a module_lib API.
620 name = "conscrypt.module.public.api"
Paul Duffin3f0290e2021-06-30 18:25:36 +0100621 } else if d, ok := module.(SdkLibraryComponentDependency); ok {
622 sdkLibraryName := d.SdkLibraryName()
623 if sdkLibraryName != nil {
624 // The module is a component of a java_sdk_library so use the name of the java_sdk_library.
625 // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then
626 // use `foo` as the name.
627 name = *sdkLibraryName
628 }
Paul Duffin280a31a2021-06-27 20:28:29 +0100629 }
630 stubDexJarsByScope := s[name]
631 if stubDexJarsByScope == nil {
632 stubDexJarsByScope = ModuleStubDexJars{}
633 s[name] = stubDexJarsByScope
634 }
635 stubDexJarsByScope[scope] = stubDexJar
636}
637
638// addStubDexJarsByModule adds the stub dex jars in the supplied StubDexJarsByModule to this map.
639func (s StubDexJarsByModule) addStubDexJarsByModule(other StubDexJarsByModule) {
640 for module, stubDexJarsByScope := range other {
641 s[module] = stubDexJarsByScope
642 }
643}
644
645// StubDexJarsForWidestAPIScope returns a list of stub dex jars containing the widest API scope
646// provided by each module.
647//
648// The relative width of APIs is determined by their order in hiddenAPIScopes.
649func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths {
650 stubDexJars := android.Paths{}
651 modules := android.SortedStringKeys(s)
652 for _, module := range modules {
653 stubDexJarsByScope := s[module]
654
655 stubDexJars = append(stubDexJars, stubDexJarsByScope.stubDexJarForWidestAPIScope())
656 }
657
658 return stubDexJars
659}
660
661// StubDexJarsForScope returns a list of stub dex jars containing the stub dex jars provided by each
662// module for the specified scope.
663//
664// If a module does not provide a stub dex jar for the supplied scope then it does not contribute to
665// the returned list.
666func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths {
667 stubDexJars := android.Paths{}
668 modules := android.SortedStringKeys(s)
669 for _, module := range modules {
670 stubDexJarsByScope := s[module]
671 // Not every module will have the same set of
672 if jars, ok := stubDexJarsByScope[scope]; ok {
673 stubDexJars = append(stubDexJars, jars)
674 }
675 }
676
677 return stubDexJars
678}
679
Paul Duffin1352f7c2021-05-21 22:18:49 +0100680// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
681// needed for hidden API flag generation.
682type HiddenAPIFlagInput struct {
683 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
684 // from the stub dex files.
685 FlagFilesByCategory FlagFilesByCategory
686
Paul Duffin31fad802021-06-18 18:14:25 +0100687 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
Paul Duffin1352f7c2021-05-21 22:18:49 +0100688 // the initial flags for each dex member.
Paul Duffin280a31a2021-06-27 20:28:29 +0100689 StubDexJarsByScope StubDexJarsByModule
Paul Duffinf1b358c2021-05-17 07:38:47 +0100690
Paul Duffin31fad802021-06-18 18:14:25 +0100691 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
692 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
Paul Duffinf1b358c2021-05-17 07:38:47 +0100693 // fragment on which this depends.
Paul Duffin280a31a2021-06-27 20:28:29 +0100694 DependencyStubDexJarsByScope StubDexJarsByModule
Paul Duffin32cf58a2021-05-18 16:32:50 +0100695
Paul Duffin5cca7c42021-05-26 10:16:01 +0100696 // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to
697 // the ones that are obtained from fragments on which this depends.
698 //
699 // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope
700 // as there are not propagated transitively to other fragments that depend on this.
Paul Duffin280a31a2021-06-27 20:28:29 +0100701 AdditionalStubDexJarsByScope StubDexJarsByModule
Paul Duffin5cca7c42021-05-26 10:16:01 +0100702
Paul Duffin32cf58a2021-05-18 16:32:50 +0100703 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
704 // specified in the bootclasspath_fragment's stub_libs and contents properties.
705 RemovedTxtFiles android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100706}
707
708// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
709func newHiddenAPIFlagInput() HiddenAPIFlagInput {
710 input := HiddenAPIFlagInput{
Paul Duffin31fad802021-06-18 18:14:25 +0100711 FlagFilesByCategory: FlagFilesByCategory{},
Paul Duffin280a31a2021-06-27 20:28:29 +0100712 StubDexJarsByScope: StubDexJarsByModule{},
713 DependencyStubDexJarsByScope: StubDexJarsByModule{},
714 AdditionalStubDexJarsByScope: StubDexJarsByModule{},
Paul Duffin1352f7c2021-05-21 22:18:49 +0100715 }
716
717 return input
718}
719
720// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
721// dependencies added in hiddenAPIAddStubLibDependencies.
722//
723// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
724func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
Paul Duffin31fad802021-06-18 18:14:25 +0100725 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
726 sdkKind := apiScope.sdkKind
727 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100728 if dexJar != nil {
Paul Duffin280a31a2021-06-27 20:28:29 +0100729 i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100730 }
Paul Duffin32cf58a2021-05-18 16:32:50 +0100731
732 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100733 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
Paul Duffin32cf58a2021-05-18 16:32:50 +0100734 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
735 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100736 }
737
738 // If the contents includes any java_sdk_library modules then add them to the stubs.
739 for _, module := range contents {
740 if _, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100741 // Add information for every possible API scope needed by hidden API.
742 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
743 addFromModule(ctx, module, apiScope)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100744 }
745 }
746 }
747
Paul Duffind061d402021-06-07 21:36:01 +0100748 ctx.VisitDirectDeps(func(module android.Module) {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100749 tag := ctx.OtherModuleDependencyTag(module)
750 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100751 apiScope := hiddenAPIStubsTag.apiScope
Paul Duffin5cca7c42021-05-26 10:16:01 +0100752 if hiddenAPIStubsTag.fromAdditionalDependency {
753 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind)
754 if dexJar != nil {
Paul Duffin280a31a2021-06-27 20:28:29 +0100755 i.AdditionalStubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar)
Paul Duffin5cca7c42021-05-26 10:16:01 +0100756 }
757 } else {
758 addFromModule(ctx, module, apiScope)
759 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100760 }
761 })
762
763 // Normalize the paths, i.e. remove duplicates and sort.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100764 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100765}
766
767// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
768// supplied properties and stores them in this struct.
769func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100770 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100771 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
772 i.FlagFilesByCategory[category] = paths
773 }
774}
775
Paul Duffin280a31a2021-06-27 20:28:29 +0100776func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule {
Paul Duffin31fad802021-06-18 18:14:25 +0100777 transitive := i.DependencyStubDexJarsByScope
Paul Duffin280a31a2021-06-27 20:28:29 +0100778 transitive.addStubDexJarsByModule(i.StubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100779 return transitive
780}
781
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100782// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
783// bootclasspath_fragment module.
784type HiddenAPIFlagOutput struct {
785 // The path to the generated stub-flags.csv file.
786 StubFlagsPath android.Path
787
788 // The path to the generated annotation-flags.csv file.
789 AnnotationFlagsPath android.Path
790
791 // The path to the generated metadata.csv file.
792 MetadataPath android.Path
793
794 // The path to the generated index.csv file.
795 IndexPath android.Path
796
797 // The path to the generated all-flags.csv file.
798 AllFlagsPath android.Path
Paul Duffin67b9d612021-07-21 17:38:47 +0100799
800 // The path to the generated signature-patterns.txt file which defines the subset of the
801 // monolithic hidden API files provided in this.
802 SignaturePatternsPath android.Path
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100803}
804
Paul Duffin5f148ca2021-06-02 17:24:22 +0100805// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
806// path.
807type bootDexJarByModule map[string]android.Path
808
809// addPath adds the path for a module to the map.
810func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
811 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
812}
813
Paul Duffine5218812021-06-07 13:28:19 +0100814// bootDexJars returns the boot dex jar paths sorted by their keys.
815func (b bootDexJarByModule) bootDexJars() android.Paths {
816 paths := android.Paths{}
817 for _, k := range android.SortedStringKeys(b) {
818 paths = append(paths, b[k])
819 }
820 return paths
821}
822
Paul Duffin7f872162021-06-17 19:33:24 +0100823// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
824// libraries if present.
825func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
826 paths := android.Paths{}
827 for _, k := range android.SortedStringKeys(b) {
828 if k == "jacocoagent" {
829 continue
830 }
831 paths = append(paths, b[k])
832 }
833 return paths
834}
835
Paul Duffine5218812021-06-07 13:28:19 +0100836// HiddenAPIOutput encapsulates the output from the hidden API processing.
837type HiddenAPIOutput struct {
838 HiddenAPIFlagOutput
839
840 // The map from base module name to the path to the encoded boot dex file.
841 EncodedBootDexFilesByModule bootDexJarByModule
842}
843
Paul Duffindfa10832021-05-13 17:31:51 +0100844// pathForValidation creates a path of the same type as the supplied type but with a name of
845// <path>.valid.
846//
847// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
848// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
849func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
850 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
851 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
852}
853
Paul Duffin2fef1362021-04-15 13:32:00 +0100854// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
855// the flags from all the modules, the stub flags, augmented with some additional configuration
856// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100857//
858// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
859// an entry for every single member in the dex implementation jars of the individual modules. Every
860// signature in any of the other files MUST be included in this file.
861//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100862// annotationFlags is the path to the annotation flags file generated from annotation information
863// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100864//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100865// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100866// the annotationFlags.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100867func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
Paul Duffind061d402021-06-07 21:36:01 +0100868 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
Paul Duffin67b9d612021-07-21 17:38:47 +0100869 flagFilesByCategory FlagFilesByCategory, flagSubsets SignatureCsvSubsets, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100870
Paul Duffindfa10832021-05-13 17:31:51 +0100871 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100872 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100873 rule := android.NewRuleBuilder(pctx, ctx)
874 command := rule.Command().
875 BuiltTool("generate_hiddenapi_lists").
876 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffind061d402021-06-07 21:36:01 +0100877 Inputs(annotationFlagPaths).
Paul Duffin702210b2021-04-08 20:12:41 +0100878 FlagWithOutput("--output ", tempPath)
879
Paul Duffine3dc6602021-04-14 09:50:43 +0100880 // Add the options for the different categories of flag files.
Paul Duffin524c82c2021-06-09 14:39:28 +0100881 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100882 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100883 for _, path := range paths {
884 category.commandMutator(command, path)
885 }
Paul Duffin702210b2021-04-08 20:12:41 +0100886 }
887
Paul Duffin32cf58a2021-05-18 16:32:50 +0100888 // If available then pass the automatically generated file containing dex signatures of removed
889 // API members to the rule so they can be marked as removed.
890 if generatedRemovedDexSignatures.Valid() {
891 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
892 }
893
Paul Duffin702210b2021-04-08 20:12:41 +0100894 commitChangeForRestat(rule, tempPath, outputPath)
895
Paul Duffin2e880972021-06-23 23:29:09 +0100896 // If there are flag files that have been generated by fragments on which this depends then use
897 // them to validate the flag file generated by the rules created by this method.
Paul Duffin67b9d612021-07-21 17:38:47 +0100898 if len(flagSubsets) > 0 {
899 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, flagSubsets)
Paul Duffin2e880972021-06-23 23:29:09 +0100900
Paul Duffindfa10832021-05-13 17:31:51 +0100901 // Add the file that indicates that the file generated by this is valid.
902 //
903 // This will cause the validation rule above to be run any time that the output of this rule
904 // changes but the validation will run in parallel with other rules that depend on this file.
905 command.Validation(validFile)
906 }
907
Paul Duffin2fef1362021-04-15 13:32:00 +0100908 rule.Build(name, desc)
909}
910
Paul Duffin67b9d612021-07-21 17:38:47 +0100911// SignatureCsvSubset describes a subset of a monolithic flags file, i.e. either
912// out/soong/hiddenapi/hiddenapi-stub-flags.txt or out/soong/hiddenapi/hiddenapi-flags.csv
913type SignatureCsvSubset struct {
914 // The path to the CSV file containing hidden API flags.
915 //
916 // It has the dex member signature as the first column, with flags, one per column, in the
917 // subsequent columns.
918 CsvFile android.Path
919
920 // The path to the CSV file containing the signature patterns.
921 //
922 // It is a single column CSV file with the column containing a signature pattern.
923 SignaturePatternsFile android.Path
924}
925
926type SignatureCsvSubsets []SignatureCsvSubset
927
928func (s SignatureCsvSubsets) RelativeToTop() []string {
929 result := []string{}
930 for _, subset := range s {
931 result = append(result, fmt.Sprintf("%s:%s", subset.CsvFile.RelativeToTop(), subset.SignaturePatternsFile.RelativeToTop()))
932 }
933 return result
934}
935
936// buildRuleSignaturePatternsFile creates a rule to generate a file containing the set of signature
937// patterns that will select a subset of the monolithic flags.
938func buildRuleSignaturePatternsFile(ctx android.ModuleContext, flagsPath android.Path) android.Path {
939 patternsFile := android.PathForModuleOut(ctx, "modular-hiddenapi", "signature-patterns.csv")
940 // Create a rule to validate the output from the following rule.
941 rule := android.NewRuleBuilder(pctx, ctx)
942 rule.Command().
943 BuiltTool("signature_patterns").
944 FlagWithInput("--flags ", flagsPath).
945 FlagWithOutput("--output ", patternsFile)
946 rule.Build("hiddenAPISignaturePatterns", "hidden API signature patterns")
947
948 return patternsFile
949}
950
Paul Duffin280bae62021-07-20 18:03:53 +0100951// buildRuleRemoveBlockedFlag creates a rule that will remove entries from the input path which
952// only have blocked flags. It will not remove entries that have blocked as well as other flags,
953// e.g. blocked,core-platform-api.
954func buildRuleRemoveBlockedFlag(ctx android.BuilderContext, name string, desc string, inputPath android.Path, filteredPath android.WritablePath) {
955 rule := android.NewRuleBuilder(pctx, ctx)
956 rule.Command().
957 Text(`grep -vE "^[^,]+,blocked$"`).Input(inputPath).Text(">").Output(filteredPath).
958 // Grep's exit code depends on whether it finds anything. It is 0 (build success) when it finds
959 // something and 1 (build failure) when it does not and 2 (when it encounters an error).
960 // However, while it is unlikely it is not an error if this does not find any matches. The
961 // following will only run if the grep does not find something and in that case it will treat
962 // an exit code of 1 as success and anything else as failure.
963 Text("|| test $? -eq 1")
964 rule.Build(name, desc)
965}
966
Paul Duffin2e880972021-06-23 23:29:09 +0100967// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated
968// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file.
Paul Duffin67b9d612021-07-21 17:38:47 +0100969func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, csvSubsets SignatureCsvSubsets) android.WritablePath {
Paul Duffin2e880972021-06-23 23:29:09 +0100970 // The file which is used to record that the flags file is valid.
971 validFile := pathForValidation(ctx, monolithicFilePath)
972
973 // Create a rule to validate the output from the following rule.
974 rule := android.NewRuleBuilder(pctx, ctx)
Paul Duffin67b9d612021-07-21 17:38:47 +0100975 command := rule.Command().
Paul Duffin2e880972021-06-23 23:29:09 +0100976 BuiltTool("verify_overlaps").
Paul Duffin67b9d612021-07-21 17:38:47 +0100977 Input(monolithicFilePath)
978
979 for _, subset := range csvSubsets {
980 command.
981 Textf("%s:%s", subset.CsvFile, subset.SignaturePatternsFile).
982 Implicit(subset.CsvFile).Implicit(subset.SignaturePatternsFile)
983 }
984
985 // If validation passes then update the file that records that.
986 command.Text("&& touch").Output(validFile)
Paul Duffin2e880972021-06-23 23:29:09 +0100987 rule.Build(name+"Validation", desc+" validation")
988
989 return validFile
990}
991
Paul Duffine5218812021-06-07 13:28:19 +0100992// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
993// bootclasspath and then encode the flags into the boot dex files.
Paul Duffin2fef1362021-04-15 13:32:00 +0100994//
995// It takes:
996// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
997// * The list of modules that are the contents of the fragment.
998// * The additional manually curated flag files to use.
999//
1000// It generates:
1001// * stub-flags.csv
1002// * annotation-flags.csv
1003// * metadata.csv
1004// * index.csv
1005// * all-flags.csv
Paul Duffine5218812021-06-07 13:28:19 +01001006// * encoded boot dex files
1007func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +01001008 hiddenApiSubDir := "modular-hiddenapi"
1009
Paul Duffine5218812021-06-07 13:28:19 +01001010 // Gather information about the boot dex files for the boot libraries provided by this fragment.
1011 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
Paul Duffin1352f7c2021-05-21 22:18:49 +01001012
1013 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +01001014 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffin2e880972021-06-23 23:29:09 +01001015 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil)
Paul Duffin2fef1362021-04-15 13:32:00 +01001016
Paul Duffin537ea3d2021-05-14 10:38:00 +01001017 // Extract the classes jars from the contents.
Paul Duffindd5993f2021-06-10 10:18:22 +01001018 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001019
Paul Duffin2fef1362021-04-15 13:32:00 +01001020 // Generate the set of flags from the annotations in the source code.
1021 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001022 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001023
1024 // Generate the metadata from the annotations in the source code.
1025 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001026 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001027
Paul Duffin537ea3d2021-05-14 10:38:00 +01001028 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +01001029 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +01001030 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +01001031
Paul Duffinaf99afa2021-05-21 22:18:56 +01001032 // 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 +01001033 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
1034 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin32cf58a2021-05-18 16:32:50 +01001035 // signatures, see the combined-removed-dex module. This does that automatically by using the
1036 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
1037 // stub_libs and contents properties of a bootclasspath_fragment.
1038 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +01001039
1040 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
1041 // files.
Paul Duffine5218812021-06-07 13:28:19 +01001042 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
Paul Duffind061d402021-06-07 21:36:01 +01001043 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
Paul Duffine5218812021-06-07 13:28:19 +01001044
1045 // Encode the flags into the boot dex files.
1046 encodedBootDexJarsByModule := map[string]android.Path{}
1047 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
1048 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
1049 bootDexInfo := bootDexInfoByModule[name]
1050 unencodedDex := bootDexInfo.path
1051 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
1052 encodedBootDexJarsByModule[name] = encodedDex
1053 }
Paul Duffin2fef1362021-04-15 13:32:00 +01001054
Paul Duffin280bae62021-07-20 18:03:53 +01001055 // Generate the filtered-stub-flags.csv file which contains the filtered stub flags that will be
1056 // compared against the monolithic stub flags.
1057 filteredStubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-stub-flags.csv")
1058 buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredStubFlags", "modular hiddenapi filtered stub flags", stubFlagsCSV, filteredStubFlagsCSV)
1059
1060 // Generate the filtered-flags.csv file which contains the filtered flags that will be compared
1061 // against the monolithic flags.
1062 filteredFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "filtered-flags.csv")
1063 buildRuleRemoveBlockedFlag(ctx, "modularHiddenApiFilteredFlags", "modular hiddenapi filtered flags", allFlagsCSV, filteredFlagsCSV)
1064
Paul Duffin2fef1362021-04-15 13:32:00 +01001065 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffine5218812021-06-07 13:28:19 +01001066 output := HiddenAPIOutput{
1067 HiddenAPIFlagOutput: HiddenAPIFlagOutput{
Paul Duffin280bae62021-07-20 18:03:53 +01001068 StubFlagsPath: filteredStubFlagsCSV,
Paul Duffine5218812021-06-07 13:28:19 +01001069 AnnotationFlagsPath: annotationFlagsCSV,
1070 MetadataPath: metadataCSV,
1071 IndexPath: indexCSV,
Paul Duffin280bae62021-07-20 18:03:53 +01001072 AllFlagsPath: filteredFlagsCSV,
Paul Duffine5218812021-06-07 13:28:19 +01001073 },
1074 EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
Paul Duffin1e6f5c42021-05-21 16:15:31 +01001075 }
1076 return &output
Paul Duffin702210b2021-04-08 20:12:41 +01001077}
Paul Duffin537ea3d2021-05-14 10:38:00 +01001078
Paul Duffin32cf58a2021-05-18 16:32:50 +01001079func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
1080 if len(removedTxtFiles) == 0 {
1081 return android.OptionalPath{}
1082 }
1083
1084 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
1085
1086 rule := android.NewRuleBuilder(pctx, ctx)
1087 rule.Command().
1088 BuiltTool("metalava").
1089 Flag("--no-banner").
1090 Inputs(removedTxtFiles).
1091 FlagWithOutput("--dex-api ", output)
1092 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
1093 return android.OptionalPathForPath(output)
1094}
1095
Paul Duffindd5993f2021-06-10 10:18:22 +01001096// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffine5218812021-06-07 13:28:19 +01001097func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1098 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +01001099 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +01001100 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
1101 if hiddenAPIModule == nil {
1102 continue
1103 }
Paul Duffine5218812021-06-07 13:28:19 +01001104 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
1105 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001106 }
1107 return bootDexJars
1108}
1109
Paul Duffindd5993f2021-06-10 10:18:22 +01001110func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
1111 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
1112 return hiddenAPIModule
1113 } else if _, ok := module.(*DexImport); ok {
1114 // Ignore this for the purposes of hidden API processing
1115 } else {
1116 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
1117 }
1118
1119 return nil
1120}
1121
Paul Duffine5218812021-06-07 13:28:19 +01001122// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
1123type bootDexInfo struct {
1124 // The path to the dex jar that has not had hidden API flags encoded into it.
1125 path android.Path
1126
1127 // Indicates whether the dex jar needs uncompressing before encoding.
1128 uncompressDex bool
1129}
1130
1131// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
1132// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
1133type bootDexInfoByModule map[string]bootDexInfo
1134
1135// bootDexJars returns the boot dex jar paths sorted by their keys.
1136func (b bootDexInfoByModule) bootDexJars() android.Paths {
1137 paths := android.Paths{}
1138 for _, m := range android.SortedStringKeys(b) {
1139 paths = append(paths, b[m].path)
1140 }
1141 return paths
1142}
1143
1144// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
1145// each of the supplied modules which must implement hiddenAPIModule.
1146func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
1147 bootDexJarsByModule := bootDexInfoByModule{}
1148 for _, module := range contents {
1149 hiddenAPIModule := module.(hiddenAPIModule)
1150 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
1151 bootDexJarsByModule[module.Name()] = bootDexInfo{
1152 path: bootDexJar,
1153 uncompressDex: *hiddenAPIModule.uncompressDex(),
1154 }
1155 }
1156
1157 return bootDexJarsByModule
1158}
1159
1160// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
1161//
1162// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
1163// create a fake path and either report an error immediately or defer reporting of the error until
1164// the path is actually used.
1165func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
1166 bootDexJar := module.bootDexJar()
1167 if bootDexJar == nil {
1168 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
1169 bootDexJar = fake
1170
1171 handleMissingDexBootFile(ctx, module, fake)
1172 }
1173 return bootDexJar
1174}
1175
Paul Duffindd5993f2021-06-10 10:18:22 +01001176// extractClassesJarsFromModules extracts the class jars from the supplied modules.
1177func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +01001178 classesJars := android.Paths{}
1179 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +01001180 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +01001181 }
1182 return classesJars
1183}
Paul Duffin5f148ca2021-06-02 17:24:22 +01001184
Paul Duffindd5993f2021-06-10 10:18:22 +01001185// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
1186func retrieveClassesJarsFromModule(module android.Module) android.Paths {
1187 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
1188 return hiddenAPIModule.classesJars()
1189 }
1190
1191 return nil
1192}
1193
Paul Duffin5f148ca2021-06-02 17:24:22 +01001194// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
1195// Soong but should instead only be reported in ninja if the file is actually built.
1196func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
1197 // TODO(b/179354495): Remove this workaround when it is unnecessary.
1198 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
1199 // create a fake one that will cause a build error only if it is used.
1200 if ctx.Config().AlwaysUsePrebuiltSdks() {
1201 return true
1202 }
1203
Paul Duffine5218812021-06-07 13:28:19 +01001204 // Any missing dependency should be allowed.
1205 if ctx.Config().AllowMissingDependencies() {
1206 return true
1207 }
1208
Paul Duffinef083c92021-06-29 13:36:34 +01001209 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
1210 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
1211 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
1212 // failures missing boot dex jars need to be deferred.
1213 if android.IsModuleInVersionedSdk(ctx.Module()) {
1214 return true
1215 }
1216
Paul Duffin5f148ca2021-06-02 17:24:22 +01001217 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
1218 //
1219 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
1220 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
1221 // but unfortunately, due to b/187910671 it does.
1222 //
1223 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
1224 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
1225 // has an APEX variant not a platform variant.
1226 //
1227 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
1228 // provide a boot dex jar:
1229 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
1230 // does not have an APEX variant and only has a platform variant and neither do its content
1231 // modules.
1232 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
1233 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
1234 // of an apex they cannot provide a boot dex jar.
1235 //
1236 // The first case causes problems when the affected prebuilt modules are preferred but that is an
1237 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
1238 // complete. The second case is used for building targets that do not use boot dex jars and so
1239 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
1240 // That is handled above.
1241 //
1242 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
1243 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
1244 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
1245 // that if the library can be part of an APEX then it is the APEX variant that is used.
1246 //
1247 // This check handles the slightly different requirements of the bootclasspath_fragment and
1248 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
1249 // a prebuilt modules that has other variants which are part of an APEX.
1250 //
1251 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
1252 if android.IsModulePrebuilt(module) {
Paul Duffinef083c92021-06-29 13:36:34 +01001253 // An inactive source module can still contribute to the APEX but an inactive prebuilt module
1254 // should not contribute to anything. So, rather than have a missing dex jar cause a Soong
1255 // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly
1256 // built Ninja should never use the dex jar file.
1257 if !isActiveModule(module) {
1258 return true
1259 }
1260
Paul Duffin5f148ca2021-06-02 17:24:22 +01001261 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
1262 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
1263 if apexInfo.IsForPlatform() {
1264 return true
1265 }
1266 }
1267 }
1268
Paul Duffin5f148ca2021-06-02 17:24:22 +01001269 return false
1270}
1271
1272// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
1273// file depending on the value returned from deferReportingMissingBootDexJar.
1274func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
1275 if deferReportingMissingBootDexJar(ctx, module) {
1276 // Create an error rule that pretends to create the output file but will actually fail if it
1277 // is run.
1278 ctx.Build(pctx, android.BuildParams{
1279 Rule: android.ErrorRule,
1280 Output: fake,
1281 Args: map[string]string{
1282 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
1283 },
1284 })
1285 } else {
1286 ctx.ModuleErrorf("module %s does not provide a dex jar", module)
1287 }
1288}
1289
1290// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
1291// DexJarBuildPath() method.
1292//
1293// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
1294// However, under certain conditions, e.g. errors, or special build configurations it will return
1295// a path to a fake file.
1296func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
1297 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
1298 if bootDexJar == nil {
1299 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
1300 bootDexJar = fake
1301
1302 handleMissingDexBootFile(ctx, module, fake)
1303 }
1304 return bootDexJar
1305}
1306
1307// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
1308func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1309 encodedDexJarsByModuleName := bootDexJarByModule{}
1310 for _, module := range contents {
1311 path := retrieveEncodedBootDexJarFromModule(ctx, module)
1312 encodedDexJarsByModuleName.addPath(module, path)
1313 }
1314 return encodedDexJarsByModuleName
1315}