blob: 66f4fe714a3d83135bd82ee98b33564f7f09482d [file] [log] [blame]
Paul Duffinc6bb7cf2021-04-08 17:49:27 +01001// Copyright (C) 2021 The Android Open Source Project
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package java
16
17import (
Paul Duffin7487a7a2021-05-19 09:36:09 +010018 "fmt"
Paul Duffindfa10832021-05-13 17:31:51 +010019 "strings"
20
Paul Duffinc6bb7cf2021-04-08 17:49:27 +010021 "android/soong/android"
Paul Duffin9b381ef2021-04-08 23:01:37 +010022 "github.com/google/blueprint"
Paul Duffin62370922021-05-23 16:55:37 +010023 "github.com/google/blueprint/proptools"
Paul Duffinc6bb7cf2021-04-08 17:49:27 +010024)
25
26// Contains support for processing hiddenAPI in a modular fashion.
27
Paul Duffin31fad802021-06-18 18:14:25 +010028// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API
29// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do
30// not provide the information needed by hidden API processing.
31type HiddenAPIScope struct {
32 // The name of the scope, used for debug purposes.
33 name string
34
35 // The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules.
36 sdkKind android.SdkKind
37
38 // The option needed to passed to "hiddenapi list".
39 hiddenAPIListOption string
40}
41
42// initHiddenAPIScope initializes the scope.
43func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope {
44 return apiScope
45}
46
47func (l *HiddenAPIScope) String() string {
48 return fmt.Sprintf("HiddenAPIScope{%s}", l.name)
49}
50
51var (
52 PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
53 name: "public",
54 sdkKind: android.SdkPublic,
55 hiddenAPIListOption: "--public-stub-classpath",
56 })
57 SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
58 name: "system",
59 sdkKind: android.SdkSystem,
60 hiddenAPIListOption: "--system-stub-classpath",
61 })
62 TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
63 name: "test",
64 sdkKind: android.SdkTest,
65 hiddenAPIListOption: "--test-stub-classpath",
66 })
67 CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{
68 name: "core-platform",
69 sdkKind: android.SdkCorePlatform,
70 hiddenAPIListOption: "--core-platform-stub-classpath",
71 })
72
73 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
74 // API processing.
75 //
76 // These are roughly in order from narrowest API surface to widest. Widest means the API stubs
77 // with the biggest API surface, e.g. test is wider than system is wider than public.
78 //
79 // Core platform is considered wider than system because those modules that provide core platform
80 // APIs either do not have any system APIs at all, or if they do it is because the core platform
81 // API is being converted to system APIs. In either case the system API is a subset of core
82 // platform API.
83 //
84 // This is not strictly in order from narrowest to widest as the Test API is wider than system but
85 // is neither wider or narrower than the core platform API. However, this works well enough at the
86 // moment.
87 // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs.
88 hiddenAPIScopes = []*HiddenAPIScope{
89 PublicHiddenAPIScope,
90 SystemHiddenAPIScope,
91 TestHiddenAPIScope,
92 CorePlatformHiddenAPIScope,
93 }
94
95 // The HiddenAPIScope instances that are supported by a java_sdk_library.
96 //
97 // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support
98 // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope.
99 hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{
100 PublicHiddenAPIScope,
101 SystemHiddenAPIScope,
102 TestHiddenAPIScope,
103 }
104
105 // The HiddenAPIScope instances that are supported by the `hiddenapi list`.
106 hiddenAPIFlagScopes = []*HiddenAPIScope{
107 PublicHiddenAPIScope,
108 SystemHiddenAPIScope,
109 TestHiddenAPIScope,
110 CorePlatformHiddenAPIScope,
111 }
112)
113
Paul Duffin74431d52021-04-21 14:10:42 +0100114type hiddenAPIStubsDependencyTag struct {
115 blueprint.BaseDependencyTag
Paul Duffin31fad802021-06-18 18:14:25 +0100116
117 // The api scope for which this dependency was added.
118 apiScope *HiddenAPIScope
Paul Duffin74431d52021-04-21 14:10:42 +0100119}
120
121func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
122}
123
124func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool {
125 return false
126}
127
Paul Duffin976b0e52021-04-27 23:20:26 +0100128func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
129 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
130 // property, otherwise treat if it was specified in the java_header_libs property.
131 if javaSdkLibrarySdkMemberType.IsInstance(child) {
132 return javaSdkLibrarySdkMemberType
133 }
134
135 return javaHeaderLibsSdkMemberType
136}
137
138func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
139 // Export the module added via this dependency tag from the sdk.
140 return true
141}
142
Paul Duffin74431d52021-04-21 14:10:42 +0100143// Avoid having to make stubs content explicitly visible to dependent modules.
144//
145// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
146// with proper dependencies.
147// TODO(b/177892522): Remove this and add needed visibility.
148func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
149}
150
151var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
152var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
153var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
Paul Duffin976b0e52021-04-27 23:20:26 +0100154var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
Paul Duffin74431d52021-04-21 14:10:42 +0100155
Paul Duffin74431d52021-04-21 14:10:42 +0100156// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
157// needed to produce the hidden API monolithic stub flags file.
Paul Duffin31fad802021-06-18 18:14:25 +0100158func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string {
Paul Duffin74431d52021-04-21 14:10:42 +0100159 var publicStubModules []string
160 var systemStubModules []string
161 var testStubModules []string
162 var corePlatformStubModules []string
163
164 if config.AlwaysUsePrebuiltSdks() {
165 // Build configuration mandates using prebuilt stub modules
166 publicStubModules = append(publicStubModules, "sdk_public_current_android")
167 systemStubModules = append(systemStubModules, "sdk_system_current_android")
168 testStubModules = append(testStubModules, "sdk_test_current_android")
169 } else {
170 // Use stub modules built from source
171 publicStubModules = append(publicStubModules, "android_stubs_current")
172 systemStubModules = append(systemStubModules, "android_system_stubs_current")
173 testStubModules = append(testStubModules, "android_test_stubs_current")
174 }
175 // We do not have prebuilts of the core platform api yet
176 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
177
178 // Allow products to define their own stubs for custom product jars that apps can use.
179 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
180 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
181 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
182 if config.IsEnvTrue("EMMA_INSTRUMENT") {
Paul Duffin098c8782021-05-14 10:45:25 +0100183 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
184 // allows everyone access but it is needed to ensure consistent flags between the
185 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
Paul Duffin74431d52021-04-21 14:10:42 +0100186 publicStubModules = append(publicStubModules, "jacoco-stubs")
Paul Duffin098c8782021-05-14 10:45:25 +0100187 systemStubModules = append(systemStubModules, "jacoco-stubs")
188 testStubModules = append(testStubModules, "jacoco-stubs")
Paul Duffin74431d52021-04-21 14:10:42 +0100189 }
190
Paul Duffin31fad802021-06-18 18:14:25 +0100191 m := map[*HiddenAPIScope][]string{}
192 m[PublicHiddenAPIScope] = publicStubModules
193 m[SystemHiddenAPIScope] = systemStubModules
194 m[TestHiddenAPIScope] = testStubModules
195 m[CorePlatformHiddenAPIScope] = corePlatformStubModules
Paul Duffin74431d52021-04-21 14:10:42 +0100196 return m
197}
198
199// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
Paul Duffin31fad802021-06-18 18:14:25 +0100200// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific
201// tag to identify the source of the dependency.
202func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) {
Paul Duffin74431d52021-04-21 14:10:42 +0100203 module := ctx.Module()
Paul Duffin31fad802021-06-18 18:14:25 +0100204 for _, apiScope := range hiddenAPIScopes {
205 modules := apiScopeToStubLibModules[apiScope]
206 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...)
Paul Duffin74431d52021-04-21 14:10:42 +0100207 }
208}
209
Paul Duffin74431d52021-04-21 14:10:42 +0100210// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
211// available, or reports an error.
Paul Duffin10931582021-04-25 10:13:54 +0100212func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
213 var dexJar android.Path
214 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
215 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
216 } else if j, ok := module.(UsesLibraryDependency); ok {
217 dexJar = j.DexJarBuildPath()
Paul Duffin74431d52021-04-21 14:10:42 +0100218 } else {
219 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 +0100220 return nil
Paul Duffin74431d52021-04-21 14:10:42 +0100221 }
Paul Duffin10931582021-04-25 10:13:54 +0100222
223 if dexJar == nil {
224 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
225 }
226 return dexJar
Paul Duffin74431d52021-04-21 14:10:42 +0100227}
228
Paul Duffin74431d52021-04-21 14:10:42 +0100229// ruleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
230//
231// The rule is initialized but not built so that the caller can modify it and select an appropriate
232// name.
Paul Duffin1352f7c2021-05-21 22:18:49 +0100233func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
Paul Duffin74431d52021-04-21 14:10:42 +0100234 // Singleton rule which applies hiddenapi on all boot class path dex files.
235 rule := android.NewRuleBuilder(pctx, ctx)
236
237 tempPath := tempPathForRestat(ctx, outputPath)
238
Paul Duffinf1b358c2021-05-17 07:38:47 +0100239 // Find the widest API stubs provided by the fragments on which this depends, if any.
240 var dependencyStubDexJars android.Paths
Paul Duffin31fad802021-06-18 18:14:25 +0100241 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- {
242 apiScope := hiddenAPIScopes[i]
243 stubsForAPIScope := input.DependencyStubDexJarsByScope[apiScope]
244 if len(stubsForAPIScope) != 0 {
245 dependencyStubDexJars = stubsForAPIScope
Paul Duffinf1b358c2021-05-17 07:38:47 +0100246 break
247 }
248 }
249
Paul Duffin74431d52021-04-21 14:10:42 +0100250 command := rule.Command().
251 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
252 Text("list").
Paul Duffinf1b358c2021-05-17 07:38:47 +0100253 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100254 FlagForEachInput("--boot-dex=", bootDexJars)
255
Paul Duffin31fad802021-06-18 18:14:25 +0100256 // Iterate over the api scopes in a fixed order.
257 for _, apiScope := range hiddenAPIFlagScopes {
258 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends.
259 // They will be needed to resolve dependencies from this fragment's stubs to classes in the
260 // other fragment's APIs.
261 var paths android.Paths
262 paths = append(paths, input.DependencyStubDexJarsByScope[apiScope]...)
263 paths = append(paths, input.StubDexJarsByScope[apiScope]...)
Paul Duffin74431d52021-04-21 14:10:42 +0100264 if len(paths) > 0 {
Paul Duffin31fad802021-06-18 18:14:25 +0100265 option := apiScope.hiddenAPIListOption
266 command.FlagWithInputList(option+"=", paths, ":")
Paul Duffin74431d52021-04-21 14:10:42 +0100267 }
268 }
269
270 // Add the output path.
271 command.FlagWithOutput("--out-api-flags=", tempPath)
272
273 commitChangeForRestat(rule, tempPath, outputPath)
274 return rule
275}
276
Paul Duffin46169772021-04-14 15:01:56 +0100277// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
278// information obtained from annotations within the source code in order to create the complete set
279// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100280//
281// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
282// of each property reference a plain text file that contains a java signature per line. The flags
283// for each of those signatures will be updated in a property specific way.
284//
285// The Unsupported_packages property contains a list of paths, each of which is a plain text file
286// with one Java package per line. All members of all classes within that package (but not nested
287// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100288type HiddenAPIFlagFileProperties struct {
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100289 // Marks each signature in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100290 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100291
292 // Marks each signature in the referenced files as being unsupported because it has been removed.
293 // Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100294 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100295
296 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
297 // and low priority.
Paul Duffin702210b2021-04-08 20:12:41 +0100298 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100299
300 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
Paul Duffin702210b2021-04-08 20:12:41 +0100301 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100302
303 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
Paul Duffin702210b2021-04-08 20:12:41 +0100304 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100305
306 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
307 // and low priority. Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100308 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100309
310 // Marks each signature in the referenced files as being blocked.
Paul Duffin702210b2021-04-08 20:12:41 +0100311 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100312
313 // Marks each signature in every package in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100314 Unsupported_packages []string `android:"path"`
315}
316
Paul Duffine3dc6602021-04-14 09:50:43 +0100317type hiddenAPIFlagFileCategory struct {
Paul Duffin524c82c2021-06-09 14:39:28 +0100318 // PropertyName is the name of the property for this category.
319 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100320
Paul Duffincc17bfe2021-04-19 13:21:20 +0100321 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100322 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100323 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100324
325 // commandMutator adds the appropriate command line options for this category to the supplied
326 // command
327 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
328}
329
Paul Duffin32cf58a2021-05-18 16:32:50 +0100330// The flag file category for removed members of the API.
331//
Paul Duffin524c82c2021-06-09 14:39:28 +0100332// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin32cf58a2021-05-18 16:32:50 +0100333// list of removed API members that are generated automatically from the removed.txt files provided
334// by API stubs.
335var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
336 // See HiddenAPIFlagFileProperties.Removed
Paul Duffin524c82c2021-06-09 14:39:28 +0100337 PropertyName: "removed",
Paul Duffin32cf58a2021-05-18 16:32:50 +0100338 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
339 return properties.Removed
340 },
341 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
342 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
343 },
344}
345
Paul Duffin524c82c2021-06-09 14:39:28 +0100346var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
Paul Duffin46169772021-04-14 15:01:56 +0100347 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100348 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100349 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100350 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100351 return properties.Unsupported
352 },
353 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
354 command.FlagWithInput("--unsupported ", path)
355 },
356 },
Paul Duffin32cf58a2021-05-18 16:32:50 +0100357 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100358 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100359 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100360 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100361 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100362 return properties.Max_target_r_low_priority
363 },
364 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
365 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
366 },
367 },
Paul Duffin46169772021-04-14 15:01:56 +0100368 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100369 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100370 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100371 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100372 return properties.Max_target_q
373 },
374 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
375 command.FlagWithInput("--max-target-q ", path)
376 },
377 },
Paul Duffin46169772021-04-14 15:01:56 +0100378 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100379 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100380 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100381 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100382 return properties.Max_target_p
383 },
384 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
385 command.FlagWithInput("--max-target-p ", path)
386 },
387 },
Paul Duffin46169772021-04-14 15:01:56 +0100388 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100389 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100390 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100391 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100392 return properties.Max_target_o_low_priority
393 },
394 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
395 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
396 },
397 },
Paul Duffin46169772021-04-14 15:01:56 +0100398 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100399 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100400 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100401 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100402 return properties.Blocked
403 },
404 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
405 command.FlagWithInput("--blocked ", path)
406 },
407 },
Paul Duffin46169772021-04-14 15:01:56 +0100408 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100409 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100410 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100411 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100412 return properties.Unsupported_packages
413 },
414 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
415 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
416 },
417 },
Paul Duffin702210b2021-04-08 20:12:41 +0100418}
419
Paul Duffin438eb572021-05-21 16:58:23 +0100420// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
421type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
422
423// append appends the supplied flags files to the corresponding category in this map.
424func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100425 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100426 s[category] = append(s[category], other[category]...)
427 }
428}
429
430// dedup removes duplicates in the flag files, while maintaining the order in which they were
431// appended.
432func (s FlagFilesByCategory) dedup() {
433 for category, paths := range s {
434 s[category] = android.FirstUniquePaths(paths)
435 }
436}
437
Paul Duffinaf99afa2021-05-21 22:18:56 +0100438// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100439//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100440// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
441// processing.
442type HiddenAPIInfo struct {
Paul Duffin438eb572021-05-21 16:58:23 +0100443 // FlagFilesByCategory maps from the flag file category to the paths containing information for
444 // that category.
445 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100446
Paul Duffin31fad802021-06-18 18:14:25 +0100447 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes.
448 TransitiveStubDexJarsByScope StubDexJarsByScope
Paul Duffin18cf1972021-05-21 22:46:59 +0100449
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100450 // The output from the hidden API processing needs to be made available to other modules.
451 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100452}
Paul Duffin702210b2021-04-08 20:12:41 +0100453
Paul Duffinf1b358c2021-05-17 07:38:47 +0100454func newHiddenAPIInfo() *HiddenAPIInfo {
455 info := HiddenAPIInfo{
Paul Duffin31fad802021-06-18 18:14:25 +0100456 FlagFilesByCategory: FlagFilesByCategory{},
457 TransitiveStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffinf1b358c2021-05-17 07:38:47 +0100458 }
459 return &info
460}
461
462func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
463 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
464 // this will introduce duplicates so they will be resolved after processing all the fragments.
465 for _, fragment := range fragments {
466 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
467 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
Paul Duffin31fad802021-06-18 18:14:25 +0100468 i.TransitiveStubDexJarsByScope.append(info.TransitiveStubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100469 }
470 }
471
472 // Dedup and sort paths.
Paul Duffin31fad802021-06-18 18:14:25 +0100473 i.TransitiveStubDexJarsByScope.dedupAndSort()
Paul Duffinf1b358c2021-05-17 07:38:47 +0100474}
475
Paul Duffinaf99afa2021-05-21 22:18:56 +0100476var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100477
Paul Duffin31fad802021-06-18 18:14:25 +0100478// StubDexJarsByScope maps a *HiddenAPIScope to the paths to stub dex jars appropriate for that
479// scope. See hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values.
480type StubDexJarsByScope map[*HiddenAPIScope]android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100481
Paul Duffin31fad802021-06-18 18:14:25 +0100482// append appends the API scope specific stub dex jar args to the corresponding scope in this
Paul Duffin1352f7c2021-05-21 22:18:49 +0100483// map.
Paul Duffin31fad802021-06-18 18:14:25 +0100484func (s StubDexJarsByScope) append(other StubDexJarsByScope) {
485 for _, scope := range hiddenAPIScopes {
486 s[scope] = append(s[scope], other[scope]...)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100487 }
488}
489
490// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
491// deterministic order.
Paul Duffin31fad802021-06-18 18:14:25 +0100492func (s StubDexJarsByScope) dedupAndSort() {
493 for apiScope, paths := range s {
494 s[apiScope] = android.SortedUniquePaths(paths)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100495 }
496}
497
498// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
499// needed for hidden API flag generation.
500type HiddenAPIFlagInput struct {
501 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
502 // from the stub dex files.
503 FlagFilesByCategory FlagFilesByCategory
504
Paul Duffin31fad802021-06-18 18:14:25 +0100505 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine
Paul Duffin1352f7c2021-05-21 22:18:49 +0100506 // the initial flags for each dex member.
Paul Duffin31fad802021-06-18 18:14:25 +0100507 StubDexJarsByScope StubDexJarsByScope
Paul Duffinf1b358c2021-05-17 07:38:47 +0100508
Paul Duffin31fad802021-06-18 18:14:25 +0100509 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this
510 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each
Paul Duffinf1b358c2021-05-17 07:38:47 +0100511 // fragment on which this depends.
Paul Duffin31fad802021-06-18 18:14:25 +0100512 DependencyStubDexJarsByScope StubDexJarsByScope
Paul Duffin32cf58a2021-05-18 16:32:50 +0100513
514 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
515 // specified in the bootclasspath_fragment's stub_libs and contents properties.
516 RemovedTxtFiles android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100517}
518
519// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
520func newHiddenAPIFlagInput() HiddenAPIFlagInput {
521 input := HiddenAPIFlagInput{
Paul Duffin31fad802021-06-18 18:14:25 +0100522 FlagFilesByCategory: FlagFilesByCategory{},
523 StubDexJarsByScope: StubDexJarsByScope{},
524 DependencyStubDexJarsByScope: StubDexJarsByScope{},
Paul Duffin1352f7c2021-05-21 22:18:49 +0100525 }
526
527 return input
528}
529
Paul Duffin62370922021-05-23 16:55:37 +0100530// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
531//
532// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
533// appropriate information needed for hidden API processing breaking the build.
534// TODO(b/179354495): Remove this workaround.
535func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
536 // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
537 // required as the whole point of adding something to the bootclasspath fragment is to add it to
538 // the bootclasspath in order to be used by something else in the system. Without any stubs it
539 // cannot do that.
Paul Duffin31fad802021-06-18 18:14:25 +0100540 if len(i.StubDexJarsByScope) == 0 {
Paul Duffin62370922021-05-23 16:55:37 +0100541 return false
542 }
543
544 // Hidden API processing is always enabled in tests.
545 if ctx.Config().TestProductVariables != nil {
546 return true
547 }
548
549 // A module that has fragments should have access to the information it needs in order to perform
550 // hidden API processing.
551 if len(properties.Fragments) != 0 {
552 return true
553 }
554
555 // The art bootclasspath fragment does not depend on any other fragments but already supports
556 // hidden API processing.
557 imageName := proptools.String(properties.Image_name)
558 if imageName == "art" {
559 return true
560 }
561
562 // Disable it for everything else.
563 return false
564}
565
Paul Duffin1352f7c2021-05-21 22:18:49 +0100566// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
567// dependencies added in hiddenAPIAddStubLibDependencies.
568//
569// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
570func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
Paul Duffin31fad802021-06-18 18:14:25 +0100571 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) {
572 sdkKind := apiScope.sdkKind
573 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100574 if dexJar != nil {
Paul Duffin31fad802021-06-18 18:14:25 +0100575 i.StubDexJarsByScope[apiScope] = append(i.StubDexJarsByScope[apiScope], dexJar)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100576 }
Paul Duffin32cf58a2021-05-18 16:32:50 +0100577
578 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100579 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind)
Paul Duffin32cf58a2021-05-18 16:32:50 +0100580 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
581 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100582 }
583
584 // If the contents includes any java_sdk_library modules then add them to the stubs.
585 for _, module := range contents {
586 if _, ok := module.(SdkLibraryDependency); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100587 // Add information for every possible API scope needed by hidden API.
588 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes {
589 addFromModule(ctx, module, apiScope)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100590 }
591 }
592 }
593
Paul Duffind061d402021-06-07 21:36:01 +0100594 ctx.VisitDirectDeps(func(module android.Module) {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100595 tag := ctx.OtherModuleDependencyTag(module)
596 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
Paul Duffin31fad802021-06-18 18:14:25 +0100597 apiScope := hiddenAPIStubsTag.apiScope
598 addFromModule(ctx, module, apiScope)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100599 }
600 })
601
602 // Normalize the paths, i.e. remove duplicates and sort.
Paul Duffin31fad802021-06-18 18:14:25 +0100603 i.StubDexJarsByScope.dedupAndSort()
604 i.DependencyStubDexJarsByScope.dedupAndSort()
Paul Duffin32cf58a2021-05-18 16:32:50 +0100605 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100606}
607
608// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
609// supplied properties and stores them in this struct.
610func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100611 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100612 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
613 i.FlagFilesByCategory[category] = paths
614 }
615}
616
Paul Duffin31fad802021-06-18 18:14:25 +0100617func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByScope {
618 transitive := i.DependencyStubDexJarsByScope
619 transitive.append(i.StubDexJarsByScope)
Paul Duffinf1b358c2021-05-17 07:38:47 +0100620 return transitive
621}
622
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100623// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
624// bootclasspath_fragment module.
625type HiddenAPIFlagOutput struct {
626 // The path to the generated stub-flags.csv file.
627 StubFlagsPath android.Path
628
629 // The path to the generated annotation-flags.csv file.
630 AnnotationFlagsPath android.Path
631
632 // The path to the generated metadata.csv file.
633 MetadataPath android.Path
634
635 // The path to the generated index.csv file.
636 IndexPath android.Path
637
638 // The path to the generated all-flags.csv file.
639 AllFlagsPath android.Path
640}
641
Paul Duffin5f148ca2021-06-02 17:24:22 +0100642// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
643// path.
644type bootDexJarByModule map[string]android.Path
645
646// addPath adds the path for a module to the map.
647func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
648 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
649}
650
Paul Duffine5218812021-06-07 13:28:19 +0100651// bootDexJars returns the boot dex jar paths sorted by their keys.
652func (b bootDexJarByModule) bootDexJars() android.Paths {
653 paths := android.Paths{}
654 for _, k := range android.SortedStringKeys(b) {
655 paths = append(paths, b[k])
656 }
657 return paths
658}
659
Paul Duffin7f872162021-06-17 19:33:24 +0100660// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage
661// libraries if present.
662func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths {
663 paths := android.Paths{}
664 for _, k := range android.SortedStringKeys(b) {
665 if k == "jacocoagent" {
666 continue
667 }
668 paths = append(paths, b[k])
669 }
670 return paths
671}
672
Paul Duffine5218812021-06-07 13:28:19 +0100673// HiddenAPIOutput encapsulates the output from the hidden API processing.
674type HiddenAPIOutput struct {
675 HiddenAPIFlagOutput
676
677 // The map from base module name to the path to the encoded boot dex file.
678 EncodedBootDexFilesByModule bootDexJarByModule
679}
680
Paul Duffindfa10832021-05-13 17:31:51 +0100681// pathForValidation creates a path of the same type as the supplied type but with a name of
682// <path>.valid.
683//
684// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
685// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
686func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
687 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
688 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
689}
690
Paul Duffin2fef1362021-04-15 13:32:00 +0100691// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
692// the flags from all the modules, the stub flags, augmented with some additional configuration
693// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100694//
695// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
696// an entry for every single member in the dex implementation jars of the individual modules. Every
697// signature in any of the other files MUST be included in this file.
698//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100699// annotationFlags is the path to the annotation flags file generated from annotation information
700// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100701//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100702// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100703// the annotationFlags.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100704func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
Paul Duffind061d402021-06-07 21:36:01 +0100705 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths,
Paul Duffin32cf58a2021-05-18 16:32:50 +0100706 flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100707
708 // The file which is used to record that the flags file is valid.
709 var validFile android.WritablePath
710
711 // If there are flag files that have been generated by fragments on which this depends then use
712 // them to validate the flag file generated by the rules created by this method.
Paul Duffin438eb572021-05-21 16:58:23 +0100713 if len(allFlagsPaths) > 0 {
Paul Duffindfa10832021-05-13 17:31:51 +0100714 // The flags file generated by the rule created by this method needs to be validated to ensure
715 // that it is consistent with the flag files generated by the individual fragments.
716
717 validFile = pathForValidation(ctx, outputPath)
718
719 // Create a rule to validate the output from the following rule.
720 rule := android.NewRuleBuilder(pctx, ctx)
721 rule.Command().
722 BuiltTool("verify_overlaps").
723 Input(outputPath).
724 Inputs(allFlagsPaths).
725 // If validation passes then update the file that records that.
726 Text("&& touch").Output(validFile)
727 rule.Build(name+"Validation", desc+" validation")
728 }
729
730 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100731 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100732 rule := android.NewRuleBuilder(pctx, ctx)
733 command := rule.Command().
734 BuiltTool("generate_hiddenapi_lists").
735 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffind061d402021-06-07 21:36:01 +0100736 Inputs(annotationFlagPaths).
Paul Duffin702210b2021-04-08 20:12:41 +0100737 FlagWithOutput("--output ", tempPath)
738
Paul Duffine3dc6602021-04-14 09:50:43 +0100739 // Add the options for the different categories of flag files.
Paul Duffin524c82c2021-06-09 14:39:28 +0100740 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100741 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100742 for _, path := range paths {
743 category.commandMutator(command, path)
744 }
Paul Duffin702210b2021-04-08 20:12:41 +0100745 }
746
Paul Duffin32cf58a2021-05-18 16:32:50 +0100747 // If available then pass the automatically generated file containing dex signatures of removed
748 // API members to the rule so they can be marked as removed.
749 if generatedRemovedDexSignatures.Valid() {
750 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
751 }
752
Paul Duffin702210b2021-04-08 20:12:41 +0100753 commitChangeForRestat(rule, tempPath, outputPath)
754
Paul Duffindfa10832021-05-13 17:31:51 +0100755 if validFile != nil {
756 // Add the file that indicates that the file generated by this is valid.
757 //
758 // This will cause the validation rule above to be run any time that the output of this rule
759 // changes but the validation will run in parallel with other rules that depend on this file.
760 command.Validation(validFile)
761 }
762
Paul Duffin2fef1362021-04-15 13:32:00 +0100763 rule.Build(name, desc)
764}
765
Paul Duffine5218812021-06-07 13:28:19 +0100766// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
767// bootclasspath and then encode the flags into the boot dex files.
Paul Duffin2fef1362021-04-15 13:32:00 +0100768//
769// It takes:
770// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
771// * The list of modules that are the contents of the fragment.
772// * The additional manually curated flag files to use.
773//
774// It generates:
775// * stub-flags.csv
776// * annotation-flags.csv
777// * metadata.csv
778// * index.csv
779// * all-flags.csv
Paul Duffine5218812021-06-07 13:28:19 +0100780// * encoded boot dex files
781func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +0100782 hiddenApiSubDir := "modular-hiddenapi"
783
Paul Duffine5218812021-06-07 13:28:19 +0100784 // Gather information about the boot dex files for the boot libraries provided by this fragment.
785 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100786
787 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +0100788 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffine5218812021-06-07 13:28:19 +0100789 rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input)
Paul Duffin2fef1362021-04-15 13:32:00 +0100790 rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
791
Paul Duffin537ea3d2021-05-14 10:38:00 +0100792 // Extract the classes jars from the contents.
Paul Duffindd5993f2021-06-10 10:18:22 +0100793 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100794
Paul Duffin2fef1362021-04-15 13:32:00 +0100795 // Generate the set of flags from the annotations in the source code.
796 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100797 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100798
799 // Generate the metadata from the annotations in the source code.
800 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100801 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100802
Paul Duffin537ea3d2021-05-14 10:38:00 +0100803 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +0100804 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100805 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100806
Paul Duffinaf99afa2021-05-21 22:18:56 +0100807 // 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 +0100808 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
809 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin32cf58a2021-05-18 16:32:50 +0100810 // signatures, see the combined-removed-dex module. This does that automatically by using the
811 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
812 // stub_libs and contents properties of a bootclasspath_fragment.
813 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +0100814
815 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
816 // files.
Paul Duffine5218812021-06-07 13:28:19 +0100817 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
Paul Duffind061d402021-06-07 21:36:01 +0100818 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures)
Paul Duffine5218812021-06-07 13:28:19 +0100819
820 // Encode the flags into the boot dex files.
821 encodedBootDexJarsByModule := map[string]android.Path{}
822 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
823 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
824 bootDexInfo := bootDexInfoByModule[name]
825 unencodedDex := bootDexInfo.path
826 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
827 encodedBootDexJarsByModule[name] = encodedDex
828 }
Paul Duffin2fef1362021-04-15 13:32:00 +0100829
830 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffine5218812021-06-07 13:28:19 +0100831 output := HiddenAPIOutput{
832 HiddenAPIFlagOutput: HiddenAPIFlagOutput{
833 StubFlagsPath: stubFlagsCSV,
834 AnnotationFlagsPath: annotationFlagsCSV,
835 MetadataPath: metadataCSV,
836 IndexPath: indexCSV,
837 AllFlagsPath: allFlagsCSV,
838 },
839 EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100840 }
841 return &output
Paul Duffin702210b2021-04-08 20:12:41 +0100842}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100843
Paul Duffin32cf58a2021-05-18 16:32:50 +0100844func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
845 if len(removedTxtFiles) == 0 {
846 return android.OptionalPath{}
847 }
848
849 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
850
851 rule := android.NewRuleBuilder(pctx, ctx)
852 rule.Command().
853 BuiltTool("metalava").
854 Flag("--no-banner").
855 Inputs(removedTxtFiles).
856 FlagWithOutput("--dex-api ", output)
857 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
858 return android.OptionalPathForPath(output)
859}
860
Paul Duffindd5993f2021-06-10 10:18:22 +0100861// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffine5218812021-06-07 13:28:19 +0100862func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
863 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100864 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +0100865 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
866 if hiddenAPIModule == nil {
867 continue
868 }
Paul Duffine5218812021-06-07 13:28:19 +0100869 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
870 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100871 }
872 return bootDexJars
873}
874
Paul Duffindd5993f2021-06-10 10:18:22 +0100875func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
876 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
877 return hiddenAPIModule
878 } else if _, ok := module.(*DexImport); ok {
879 // Ignore this for the purposes of hidden API processing
880 } else {
881 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
882 }
883
884 return nil
885}
886
Paul Duffine5218812021-06-07 13:28:19 +0100887// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
888type bootDexInfo struct {
889 // The path to the dex jar that has not had hidden API flags encoded into it.
890 path android.Path
891
892 // Indicates whether the dex jar needs uncompressing before encoding.
893 uncompressDex bool
894}
895
896// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
897// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
898type bootDexInfoByModule map[string]bootDexInfo
899
900// bootDexJars returns the boot dex jar paths sorted by their keys.
901func (b bootDexInfoByModule) bootDexJars() android.Paths {
902 paths := android.Paths{}
903 for _, m := range android.SortedStringKeys(b) {
904 paths = append(paths, b[m].path)
905 }
906 return paths
907}
908
909// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
910// each of the supplied modules which must implement hiddenAPIModule.
911func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
912 bootDexJarsByModule := bootDexInfoByModule{}
913 for _, module := range contents {
914 hiddenAPIModule := module.(hiddenAPIModule)
915 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
916 bootDexJarsByModule[module.Name()] = bootDexInfo{
917 path: bootDexJar,
918 uncompressDex: *hiddenAPIModule.uncompressDex(),
919 }
920 }
921
922 return bootDexJarsByModule
923}
924
925// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
926//
927// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
928// create a fake path and either report an error immediately or defer reporting of the error until
929// the path is actually used.
930func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
931 bootDexJar := module.bootDexJar()
932 if bootDexJar == nil {
933 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
934 bootDexJar = fake
935
936 handleMissingDexBootFile(ctx, module, fake)
937 }
938 return bootDexJar
939}
940
Paul Duffindd5993f2021-06-10 10:18:22 +0100941// extractClassesJarsFromModules extracts the class jars from the supplied modules.
942func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +0100943 classesJars := android.Paths{}
944 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +0100945 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100946 }
947 return classesJars
948}
Paul Duffin5f148ca2021-06-02 17:24:22 +0100949
Paul Duffindd5993f2021-06-10 10:18:22 +0100950// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
951func retrieveClassesJarsFromModule(module android.Module) android.Paths {
952 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
953 return hiddenAPIModule.classesJars()
954 }
955
956 return nil
957}
958
Paul Duffin5f148ca2021-06-02 17:24:22 +0100959// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
960// Soong but should instead only be reported in ninja if the file is actually built.
961func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
962 // TODO(b/179354495): Remove this workaround when it is unnecessary.
963 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
964 // create a fake one that will cause a build error only if it is used.
965 if ctx.Config().AlwaysUsePrebuiltSdks() {
966 return true
967 }
968
Paul Duffine5218812021-06-07 13:28:19 +0100969 // Any missing dependency should be allowed.
970 if ctx.Config().AllowMissingDependencies() {
971 return true
972 }
973
Paul Duffin5f148ca2021-06-02 17:24:22 +0100974 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
975 //
976 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
977 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
978 // but unfortunately, due to b/187910671 it does.
979 //
980 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
981 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
982 // has an APEX variant not a platform variant.
983 //
984 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
985 // provide a boot dex jar:
986 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
987 // does not have an APEX variant and only has a platform variant and neither do its content
988 // modules.
989 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
990 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
991 // of an apex they cannot provide a boot dex jar.
992 //
993 // The first case causes problems when the affected prebuilt modules are preferred but that is an
994 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
995 // complete. The second case is used for building targets that do not use boot dex jars and so
996 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
997 // That is handled above.
998 //
999 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
1000 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
1001 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
1002 // that if the library can be part of an APEX then it is the APEX variant that is used.
1003 //
1004 // This check handles the slightly different requirements of the bootclasspath_fragment and
1005 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
1006 // a prebuilt modules that has other variants which are part of an APEX.
1007 //
1008 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
1009 if android.IsModulePrebuilt(module) {
1010 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
1011 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
1012 if apexInfo.IsForPlatform() {
1013 return true
1014 }
1015 }
1016 }
1017
1018 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
1019 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
1020 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
1021 // failures missing boot dex jars need to be deferred.
1022 if android.IsModuleInVersionedSdk(ctx.Module()) {
1023 return true
1024 }
1025
1026 return false
1027}
1028
1029// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
1030// file depending on the value returned from deferReportingMissingBootDexJar.
1031func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
1032 if deferReportingMissingBootDexJar(ctx, module) {
1033 // Create an error rule that pretends to create the output file but will actually fail if it
1034 // is run.
1035 ctx.Build(pctx, android.BuildParams{
1036 Rule: android.ErrorRule,
1037 Output: fake,
1038 Args: map[string]string{
1039 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
1040 },
1041 })
1042 } else {
1043 ctx.ModuleErrorf("module %s does not provide a dex jar", module)
1044 }
1045}
1046
1047// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
1048// DexJarBuildPath() method.
1049//
1050// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
1051// However, under certain conditions, e.g. errors, or special build configurations it will return
1052// a path to a fake file.
1053func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
1054 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
1055 if bootDexJar == nil {
1056 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
1057 bootDexJar = fake
1058
1059 handleMissingDexBootFile(ctx, module, fake)
1060 }
1061 return bootDexJar
1062}
1063
1064// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
1065func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
1066 encodedDexJarsByModuleName := bootDexJarByModule{}
1067 for _, module := range contents {
1068 path := retrieveEncodedBootDexJarFromModule(ctx, module)
1069 encodedDexJarsByModuleName.addPath(module, path)
1070 }
1071 return encodedDexJarsByModuleName
1072}