blob: 60300afe130d8a0e9858319c0213b323c68d41b4 [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 Duffin74431d52021-04-21 14:10:42 +010028type hiddenAPIStubsDependencyTag struct {
29 blueprint.BaseDependencyTag
30 sdkKind android.SdkKind
31}
32
33func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() {
34}
35
36func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool {
37 return false
38}
39
Paul Duffin976b0e52021-04-27 23:20:26 +010040func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType {
41 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs
42 // property, otherwise treat if it was specified in the java_header_libs property.
43 if javaSdkLibrarySdkMemberType.IsInstance(child) {
44 return javaSdkLibrarySdkMemberType
45 }
46
47 return javaHeaderLibsSdkMemberType
48}
49
50func (b hiddenAPIStubsDependencyTag) ExportMember() bool {
51 // Export the module added via this dependency tag from the sdk.
52 return true
53}
54
Paul Duffin74431d52021-04-21 14:10:42 +010055// Avoid having to make stubs content explicitly visible to dependent modules.
56//
57// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules
58// with proper dependencies.
59// TODO(b/177892522): Remove this and add needed visibility.
60func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() {
61}
62
63var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{}
64var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{}
65var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{}
Paul Duffin976b0e52021-04-27 23:20:26 +010066var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{}
Paul Duffin74431d52021-04-21 14:10:42 +010067
Paul Duffin3e7fcc32021-04-15 13:31:38 +010068// hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden
69// API processing.
Paul Duffinf1b358c2021-05-17 07:38:47 +010070//
71// These are in order from narrowest API surface to widest. Widest means the API stubs with the
72// biggest API surface, e.g. test is wider than system is wider than public. Core platform is
73// considered wider than test even though it has no relationship with test because the libraries
74// that provide core platform API don't provide test. While the core platform API is being converted
75// to a system API the system API is still a subset of core platform.
Paul Duffin3e7fcc32021-04-15 13:31:38 +010076var hiddenAPIRelevantSdkKinds = []android.SdkKind{
77 android.SdkPublic,
78 android.SdkSystem,
79 android.SdkTest,
80 android.SdkCorePlatform,
81}
82
Paul Duffin74431d52021-04-21 14:10:42 +010083// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs
84// needed to produce the hidden API monolithic stub flags file.
85func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[android.SdkKind][]string {
86 var publicStubModules []string
87 var systemStubModules []string
88 var testStubModules []string
89 var corePlatformStubModules []string
90
91 if config.AlwaysUsePrebuiltSdks() {
92 // Build configuration mandates using prebuilt stub modules
93 publicStubModules = append(publicStubModules, "sdk_public_current_android")
94 systemStubModules = append(systemStubModules, "sdk_system_current_android")
95 testStubModules = append(testStubModules, "sdk_test_current_android")
96 } else {
97 // Use stub modules built from source
98 publicStubModules = append(publicStubModules, "android_stubs_current")
99 systemStubModules = append(systemStubModules, "android_system_stubs_current")
100 testStubModules = append(testStubModules, "android_test_stubs_current")
101 }
102 // We do not have prebuilts of the core platform api yet
103 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs")
104
105 // Allow products to define their own stubs for custom product jars that apps can use.
106 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...)
107 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...)
108 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...)
109 if config.IsEnvTrue("EMMA_INSTRUMENT") {
Paul Duffin098c8782021-05-14 10:45:25 +0100110 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public
111 // allows everyone access but it is needed to ensure consistent flags between the
112 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags.
Paul Duffin74431d52021-04-21 14:10:42 +0100113 publicStubModules = append(publicStubModules, "jacoco-stubs")
Paul Duffin098c8782021-05-14 10:45:25 +0100114 systemStubModules = append(systemStubModules, "jacoco-stubs")
115 testStubModules = append(testStubModules, "jacoco-stubs")
Paul Duffin74431d52021-04-21 14:10:42 +0100116 }
117
118 m := map[android.SdkKind][]string{}
119 m[android.SdkPublic] = publicStubModules
120 m[android.SdkSystem] = systemStubModules
121 m[android.SdkTest] = testStubModules
122 m[android.SdkCorePlatform] = corePlatformStubModules
123 return m
124}
125
126// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in
127// sdkKindToStubLibModules. It adds them in a well known order and uses an SdkKind specific tag to
128// identify the source of the dependency.
129func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, sdkKindToStubLibModules map[android.SdkKind][]string) {
130 module := ctx.Module()
131 for _, sdkKind := range hiddenAPIRelevantSdkKinds {
132 modules := sdkKindToStubLibModules[sdkKind]
133 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{sdkKind: sdkKind}, modules...)
134 }
135}
136
Paul Duffin74431d52021-04-21 14:10:42 +0100137// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if
138// available, or reports an error.
Paul Duffin10931582021-04-25 10:13:54 +0100139func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path {
140 var dexJar android.Path
141 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
142 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind)
143 } else if j, ok := module.(UsesLibraryDependency); ok {
144 dexJar = j.DexJarBuildPath()
Paul Duffin74431d52021-04-21 14:10:42 +0100145 } else {
146 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 +0100147 return nil
Paul Duffin74431d52021-04-21 14:10:42 +0100148 }
Paul Duffin10931582021-04-25 10:13:54 +0100149
150 if dexJar == nil {
151 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module)
152 }
153 return dexJar
Paul Duffin74431d52021-04-21 14:10:42 +0100154}
155
156var sdkKindToHiddenapiListOption = map[android.SdkKind]string{
157 android.SdkPublic: "public-stub-classpath",
158 android.SdkSystem: "system-stub-classpath",
159 android.SdkTest: "test-stub-classpath",
160 android.SdkCorePlatform: "core-platform-stub-classpath",
161}
162
163// ruleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file.
164//
165// The rule is initialized but not built so that the caller can modify it and select an appropriate
166// name.
Paul Duffin1352f7c2021-05-21 22:18:49 +0100167func ruleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput) *android.RuleBuilder {
Paul Duffin74431d52021-04-21 14:10:42 +0100168 // Singleton rule which applies hiddenapi on all boot class path dex files.
169 rule := android.NewRuleBuilder(pctx, ctx)
170
171 tempPath := tempPathForRestat(ctx, outputPath)
172
Paul Duffinf1b358c2021-05-17 07:38:47 +0100173 // Find the widest API stubs provided by the fragments on which this depends, if any.
174 var dependencyStubDexJars android.Paths
175 for i := len(hiddenAPIRelevantSdkKinds) - 1; i >= 0; i-- {
176 kind := hiddenAPIRelevantSdkKinds[i]
177 stubsForKind := input.DependencyStubDexJarsByKind[kind]
178 if len(stubsForKind) != 0 {
179 dependencyStubDexJars = stubsForKind
180 break
181 }
182 }
183
Paul Duffin74431d52021-04-21 14:10:42 +0100184 command := rule.Command().
185 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")).
186 Text("list").
Paul Duffinf1b358c2021-05-17 07:38:47 +0100187 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars).
Paul Duffin74431d52021-04-21 14:10:42 +0100188 FlagForEachInput("--boot-dex=", bootDexJars)
189
190 // Iterate over the sdk kinds in a fixed order.
191 for _, sdkKind := range hiddenAPIRelevantSdkKinds {
Paul Duffinf1b358c2021-05-17 07:38:47 +0100192 // Merge in the stub dex jar paths for this kind from the fragments on which it depends. They
193 // will be needed to resolve dependencies from this fragment's stubs to classes in the other
194 // fragment's APIs.
195 dependencyPaths := input.DependencyStubDexJarsByKind[sdkKind]
196 paths := append(dependencyPaths, input.StubDexJarsByKind[sdkKind]...)
Paul Duffin74431d52021-04-21 14:10:42 +0100197 if len(paths) > 0 {
198 option := sdkKindToHiddenapiListOption[sdkKind]
199 command.FlagWithInputList("--"+option+"=", paths, ":")
200 }
201 }
202
203 // Add the output path.
204 command.FlagWithOutput("--out-api-flags=", tempPath)
205
206 commitChangeForRestat(rule, tempPath, outputPath)
207 return rule
208}
209
Paul Duffin46169772021-04-14 15:01:56 +0100210// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the
211// information obtained from annotations within the source code in order to create the complete set
212// of flags that should be applied to the dex implementation jars on the bootclasspath.
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100213//
214// Each property contains a list of paths. With the exception of the Unsupported_packages the paths
215// of each property reference a plain text file that contains a java signature per line. The flags
216// for each of those signatures will be updated in a property specific way.
217//
218// The Unsupported_packages property contains a list of paths, each of which is a plain text file
219// with one Java package per line. All members of all classes within that package (but not nested
220// packages) will be updated in a property specific way.
Paul Duffin46169772021-04-14 15:01:56 +0100221type HiddenAPIFlagFileProperties struct {
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100222 // Marks each signature in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100223 Unsupported []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100224
225 // Marks each signature in the referenced files as being unsupported because it has been removed.
226 // Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100227 Removed []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100228
229 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R
230 // and low priority.
Paul Duffin702210b2021-04-08 20:12:41 +0100231 Max_target_r_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100232
233 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q.
Paul Duffin702210b2021-04-08 20:12:41 +0100234 Max_target_q []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100235
236 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P.
Paul Duffin702210b2021-04-08 20:12:41 +0100237 Max_target_p []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100238
239 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O
240 // and low priority. Any conflicts with other flags are ignored.
Paul Duffin702210b2021-04-08 20:12:41 +0100241 Max_target_o_low_priority []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100242
243 // Marks each signature in the referenced files as being blocked.
Paul Duffin702210b2021-04-08 20:12:41 +0100244 Blocked []string `android:"path"`
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100245
246 // Marks each signature in every package in the referenced files as being unsupported.
Paul Duffin702210b2021-04-08 20:12:41 +0100247 Unsupported_packages []string `android:"path"`
248}
249
Paul Duffine3dc6602021-04-14 09:50:43 +0100250type hiddenAPIFlagFileCategory struct {
Paul Duffin524c82c2021-06-09 14:39:28 +0100251 // PropertyName is the name of the property for this category.
252 PropertyName string
Paul Duffine3dc6602021-04-14 09:50:43 +0100253
Paul Duffincc17bfe2021-04-19 13:21:20 +0100254 // propertyValueReader retrieves the value of the property for this category from the set of
Paul Duffine3dc6602021-04-14 09:50:43 +0100255 // properties.
Paul Duffincc17bfe2021-04-19 13:21:20 +0100256 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string
Paul Duffine3dc6602021-04-14 09:50:43 +0100257
258 // commandMutator adds the appropriate command line options for this category to the supplied
259 // command
260 commandMutator func(command *android.RuleBuilderCommand, path android.Path)
261}
262
Paul Duffin32cf58a2021-05-18 16:32:50 +0100263// The flag file category for removed members of the API.
264//
Paul Duffin524c82c2021-06-09 14:39:28 +0100265// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures
Paul Duffin32cf58a2021-05-18 16:32:50 +0100266// list of removed API members that are generated automatically from the removed.txt files provided
267// by API stubs.
268var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{
269 // See HiddenAPIFlagFileProperties.Removed
Paul Duffin524c82c2021-06-09 14:39:28 +0100270 PropertyName: "removed",
Paul Duffin32cf58a2021-05-18 16:32:50 +0100271 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
272 return properties.Removed
273 },
274 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
275 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed")
276 },
277}
278
Paul Duffin524c82c2021-06-09 14:39:28 +0100279var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{
Paul Duffin46169772021-04-14 15:01:56 +0100280 // See HiddenAPIFlagFileProperties.Unsupported
Paul Duffine3dc6602021-04-14 09:50:43 +0100281 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100282 PropertyName: "unsupported",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100283 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100284 return properties.Unsupported
285 },
286 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
287 command.FlagWithInput("--unsupported ", path)
288 },
289 },
Paul Duffin32cf58a2021-05-18 16:32:50 +0100290 hiddenAPIRemovedFlagFileCategory,
Paul Duffin46169772021-04-14 15:01:56 +0100291 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100292 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100293 PropertyName: "max_target_r_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100294 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100295 return properties.Max_target_r_low_priority
296 },
297 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
298 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio")
299 },
300 },
Paul Duffin46169772021-04-14 15:01:56 +0100301 // See HiddenAPIFlagFileProperties.Max_target_q
Paul Duffine3dc6602021-04-14 09:50:43 +0100302 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100303 PropertyName: "max_target_q",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100304 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100305 return properties.Max_target_q
306 },
307 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
308 command.FlagWithInput("--max-target-q ", path)
309 },
310 },
Paul Duffin46169772021-04-14 15:01:56 +0100311 // See HiddenAPIFlagFileProperties.Max_target_p
Paul Duffine3dc6602021-04-14 09:50:43 +0100312 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100313 PropertyName: "max_target_p",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100314 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100315 return properties.Max_target_p
316 },
317 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
318 command.FlagWithInput("--max-target-p ", path)
319 },
320 },
Paul Duffin46169772021-04-14 15:01:56 +0100321 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority
Paul Duffine3dc6602021-04-14 09:50:43 +0100322 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100323 PropertyName: "max_target_o_low_priority",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100324 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100325 return properties.Max_target_o_low_priority
326 },
327 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
328 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio")
329 },
330 },
Paul Duffin46169772021-04-14 15:01:56 +0100331 // See HiddenAPIFlagFileProperties.Blocked
Paul Duffine3dc6602021-04-14 09:50:43 +0100332 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100333 PropertyName: "blocked",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100334 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100335 return properties.Blocked
336 },
337 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
338 command.FlagWithInput("--blocked ", path)
339 },
340 },
Paul Duffin46169772021-04-14 15:01:56 +0100341 // See HiddenAPIFlagFileProperties.Unsupported_packages
Paul Duffine3dc6602021-04-14 09:50:43 +0100342 {
Paul Duffin524c82c2021-06-09 14:39:28 +0100343 PropertyName: "unsupported_packages",
Paul Duffincc17bfe2021-04-19 13:21:20 +0100344 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string {
Paul Duffine3dc6602021-04-14 09:50:43 +0100345 return properties.Unsupported_packages
346 },
347 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) {
348 command.FlagWithInput("--unsupported ", path).Flag("--packages ")
349 },
350 },
Paul Duffin702210b2021-04-08 20:12:41 +0100351}
352
Paul Duffin438eb572021-05-21 16:58:23 +0100353// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category.
354type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths
355
356// append appends the supplied flags files to the corresponding category in this map.
357func (s FlagFilesByCategory) append(other FlagFilesByCategory) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100358 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100359 s[category] = append(s[category], other[category]...)
360 }
361}
362
363// dedup removes duplicates in the flag files, while maintaining the order in which they were
364// appended.
365func (s FlagFilesByCategory) dedup() {
366 for category, paths := range s {
367 s[category] = android.FirstUniquePaths(paths)
368 }
369}
370
Paul Duffinaf99afa2021-05-21 22:18:56 +0100371// HiddenAPIInfo contains information provided by the hidden API processing.
Paul Duffin2fef1362021-04-15 13:32:00 +0100372//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100373// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API
374// processing.
375type HiddenAPIInfo struct {
Paul Duffin438eb572021-05-21 16:58:23 +0100376 // FlagFilesByCategory maps from the flag file category to the paths containing information for
377 // that category.
378 FlagFilesByCategory FlagFilesByCategory
Paul Duffin2fef1362021-04-15 13:32:00 +0100379
Paul Duffin18cf1972021-05-21 22:46:59 +0100380 // The paths to the stub dex jars for each of the android.SdkKind in hiddenAPIRelevantSdkKinds.
Paul Duffinf1b358c2021-05-17 07:38:47 +0100381 TransitiveStubDexJarsByKind StubDexJarsByKind
Paul Duffin18cf1972021-05-21 22:46:59 +0100382
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100383 // The output from the hidden API processing needs to be made available to other modules.
384 HiddenAPIFlagOutput
Paul Duffinc6bb7cf2021-04-08 17:49:27 +0100385}
Paul Duffin702210b2021-04-08 20:12:41 +0100386
Paul Duffinf1b358c2021-05-17 07:38:47 +0100387func newHiddenAPIInfo() *HiddenAPIInfo {
388 info := HiddenAPIInfo{
389 FlagFilesByCategory: FlagFilesByCategory{},
390 TransitiveStubDexJarsByKind: StubDexJarsByKind{},
391 }
392 return &info
393}
394
395func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) {
396 // Merge all the information from the fragments. The fragments form a DAG so it is possible that
397 // this will introduce duplicates so they will be resolved after processing all the fragments.
398 for _, fragment := range fragments {
399 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) {
400 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo)
401 i.TransitiveStubDexJarsByKind.append(info.TransitiveStubDexJarsByKind)
402 }
403 }
404
405 // Dedup and sort paths.
406 i.TransitiveStubDexJarsByKind.dedupAndSort()
407}
408
Paul Duffinaf99afa2021-05-21 22:18:56 +0100409var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{})
Paul Duffin9b381ef2021-04-08 23:01:37 +0100410
Paul Duffin1352f7c2021-05-21 22:18:49 +0100411// StubDexJarsByKind maps an android.SdkKind to the paths to stub dex jars appropriate for that
412// level. See hiddenAPIRelevantSdkKinds for a list of the acceptable android.SdkKind values.
413type StubDexJarsByKind map[android.SdkKind]android.Paths
414
415// append appends the supplied kind specific stub dex jar pargs to the corresponding kind in this
416// map.
417func (s StubDexJarsByKind) append(other StubDexJarsByKind) {
418 for _, kind := range hiddenAPIRelevantSdkKinds {
419 s[kind] = append(s[kind], other[kind]...)
420 }
421}
422
423// dedupAndSort removes duplicates in the stub dex jar paths and sorts them into a consistent and
424// deterministic order.
425func (s StubDexJarsByKind) dedupAndSort() {
426 for kind, paths := range s {
427 s[kind] = android.SortedUniquePaths(paths)
428 }
429}
430
431// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are
432// needed for hidden API flag generation.
433type HiddenAPIFlagInput struct {
434 // FlagFilesByCategory contains the flag files that override the initial flags that are derived
435 // from the stub dex files.
436 FlagFilesByCategory FlagFilesByCategory
437
438 // StubDexJarsByKind contains the stub dex jars for different android.SdkKind and which determine
439 // the initial flags for each dex member.
440 StubDexJarsByKind StubDexJarsByKind
Paul Duffinf1b358c2021-05-17 07:38:47 +0100441
442 // DependencyStubDexJarsByKind contains the stub dex jars provided by the fragments on which this
443 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByKind from each
444 // fragment on which this depends.
445 DependencyStubDexJarsByKind StubDexJarsByKind
Paul Duffin32cf58a2021-05-18 16:32:50 +0100446
447 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are
448 // specified in the bootclasspath_fragment's stub_libs and contents properties.
449 RemovedTxtFiles android.Paths
Paul Duffin1352f7c2021-05-21 22:18:49 +0100450}
451
452// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct.
453func newHiddenAPIFlagInput() HiddenAPIFlagInput {
454 input := HiddenAPIFlagInput{
455 FlagFilesByCategory: FlagFilesByCategory{},
456 StubDexJarsByKind: StubDexJarsByKind{},
457 }
458
459 return input
460}
461
Paul Duffin62370922021-05-23 16:55:37 +0100462// canPerformHiddenAPIProcessing determines whether hidden API processing should be performed.
463//
464// A temporary workaround to avoid existing bootclasspath_fragments that do not provide the
465// appropriate information needed for hidden API processing breaking the build.
466// TODO(b/179354495): Remove this workaround.
467func (i *HiddenAPIFlagInput) canPerformHiddenAPIProcessing(ctx android.ModuleContext, properties bootclasspathFragmentProperties) bool {
468 // Performing hidden API processing without stubs is not supported and it is unlikely to ever be
469 // required as the whole point of adding something to the bootclasspath fragment is to add it to
470 // the bootclasspath in order to be used by something else in the system. Without any stubs it
471 // cannot do that.
472 if len(i.StubDexJarsByKind) == 0 {
473 return false
474 }
475
476 // Hidden API processing is always enabled in tests.
477 if ctx.Config().TestProductVariables != nil {
478 return true
479 }
480
481 // A module that has fragments should have access to the information it needs in order to perform
482 // hidden API processing.
483 if len(properties.Fragments) != 0 {
484 return true
485 }
486
487 // The art bootclasspath fragment does not depend on any other fragments but already supports
488 // hidden API processing.
489 imageName := proptools.String(properties.Image_name)
490 if imageName == "art" {
491 return true
492 }
493
494 // Disable it for everything else.
495 return false
496}
497
Paul Duffin1352f7c2021-05-21 22:18:49 +0100498// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the
499// dependencies added in hiddenAPIAddStubLibDependencies.
500//
501// That includes paths to the stub dex jars as well as paths to the *removed.txt files.
502func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) {
503 addFromModule := func(ctx android.ModuleContext, module android.Module, kind android.SdkKind) {
504 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, kind)
505 if dexJar != nil {
506 i.StubDexJarsByKind[kind] = append(i.StubDexJarsByKind[kind], dexJar)
507 }
Paul Duffin32cf58a2021-05-18 16:32:50 +0100508
509 if sdkLibrary, ok := module.(SdkLibraryDependency); ok {
510 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, kind)
511 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...)
512 }
Paul Duffin1352f7c2021-05-21 22:18:49 +0100513 }
514
515 // If the contents includes any java_sdk_library modules then add them to the stubs.
516 for _, module := range contents {
517 if _, ok := module.(SdkLibraryDependency); ok {
518 // Add information for every possible kind needed by hidden API. SdkCorePlatform is not used
519 // as the java_sdk_library does not have special support for core_platform API, instead it is
520 // implemented as a customized form of SdkPublic.
521 for _, kind := range []android.SdkKind{android.SdkPublic, android.SdkSystem, android.SdkTest} {
522 addFromModule(ctx, module, kind)
523 }
524 }
525 }
526
527 ctx.VisitDirectDepsIf(isActiveModule, func(module android.Module) {
528 tag := ctx.OtherModuleDependencyTag(module)
529 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok {
530 kind := hiddenAPIStubsTag.sdkKind
531 addFromModule(ctx, module, kind)
532 }
533 })
534
535 // Normalize the paths, i.e. remove duplicates and sort.
536 i.StubDexJarsByKind.dedupAndSort()
Paul Duffin32cf58a2021-05-18 16:32:50 +0100537 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100538}
539
540// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the
541// supplied properties and stores them in this struct.
542func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) {
Paul Duffin524c82c2021-06-09 14:39:28 +0100543 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin1352f7c2021-05-21 22:18:49 +0100544 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p))
545 i.FlagFilesByCategory[category] = paths
546 }
547}
548
Paul Duffinf1b358c2021-05-17 07:38:47 +0100549func (i *HiddenAPIFlagInput) transitiveStubDexJarsByKind() StubDexJarsByKind {
550 transitive := i.DependencyStubDexJarsByKind
551 transitive.append(i.StubDexJarsByKind)
552 return transitive
553}
554
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100555// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a
556// bootclasspath_fragment module.
557type HiddenAPIFlagOutput struct {
558 // The path to the generated stub-flags.csv file.
559 StubFlagsPath android.Path
560
561 // The path to the generated annotation-flags.csv file.
562 AnnotationFlagsPath android.Path
563
564 // The path to the generated metadata.csv file.
565 MetadataPath android.Path
566
567 // The path to the generated index.csv file.
568 IndexPath android.Path
569
570 // The path to the generated all-flags.csv file.
571 AllFlagsPath android.Path
572}
573
Paul Duffin5f148ca2021-06-02 17:24:22 +0100574// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex
575// path.
576type bootDexJarByModule map[string]android.Path
577
578// addPath adds the path for a module to the map.
579func (b bootDexJarByModule) addPath(module android.Module, path android.Path) {
580 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path
581}
582
Paul Duffine5218812021-06-07 13:28:19 +0100583// bootDexJars returns the boot dex jar paths sorted by their keys.
584func (b bootDexJarByModule) bootDexJars() android.Paths {
585 paths := android.Paths{}
586 for _, k := range android.SortedStringKeys(b) {
587 paths = append(paths, b[k])
588 }
589 return paths
590}
591
592// HiddenAPIOutput encapsulates the output from the hidden API processing.
593type HiddenAPIOutput struct {
594 HiddenAPIFlagOutput
595
596 // The map from base module name to the path to the encoded boot dex file.
597 EncodedBootDexFilesByModule bootDexJarByModule
598}
599
Paul Duffindfa10832021-05-13 17:31:51 +0100600// pathForValidation creates a path of the same type as the supplied type but with a name of
601// <path>.valid.
602//
603// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return
604// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid
605func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath {
606 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".")
607 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid")
608}
609
Paul Duffin2fef1362021-04-15 13:32:00 +0100610// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from
611// the flags from all the modules, the stub flags, augmented with some additional configuration
612// files.
Paul Duffin702210b2021-04-08 20:12:41 +0100613//
614// baseFlagsPath is the path to the flags file containing all the information from the stubs plus
615// an entry for every single member in the dex implementation jars of the individual modules. Every
616// signature in any of the other files MUST be included in this file.
617//
Paul Duffin537ea3d2021-05-14 10:38:00 +0100618// annotationFlags is the path to the annotation flags file generated from annotation information
619// in each module.
Paul Duffin702210b2021-04-08 20:12:41 +0100620//
Paul Duffinaf99afa2021-05-21 22:18:56 +0100621// hiddenAPIInfo is a struct containing paths to files that augment the information provided by
Paul Duffin537ea3d2021-05-14 10:38:00 +0100622// the annotationFlags.
Paul Duffin32cf58a2021-05-18 16:32:50 +0100623func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string,
624 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlags android.Path,
625 flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) {
Paul Duffindfa10832021-05-13 17:31:51 +0100626
627 // The file which is used to record that the flags file is valid.
628 var validFile android.WritablePath
629
630 // If there are flag files that have been generated by fragments on which this depends then use
631 // them to validate the flag file generated by the rules created by this method.
Paul Duffin438eb572021-05-21 16:58:23 +0100632 if len(allFlagsPaths) > 0 {
Paul Duffindfa10832021-05-13 17:31:51 +0100633 // The flags file generated by the rule created by this method needs to be validated to ensure
634 // that it is consistent with the flag files generated by the individual fragments.
635
636 validFile = pathForValidation(ctx, outputPath)
637
638 // Create a rule to validate the output from the following rule.
639 rule := android.NewRuleBuilder(pctx, ctx)
640 rule.Command().
641 BuiltTool("verify_overlaps").
642 Input(outputPath).
643 Inputs(allFlagsPaths).
644 // If validation passes then update the file that records that.
645 Text("&& touch").Output(validFile)
646 rule.Build(name+"Validation", desc+" validation")
647 }
648
649 // Create the rule that will generate the flag files.
Paul Duffind3c15132021-04-21 22:12:35 +0100650 tempPath := tempPathForRestat(ctx, outputPath)
Paul Duffin702210b2021-04-08 20:12:41 +0100651 rule := android.NewRuleBuilder(pctx, ctx)
652 command := rule.Command().
653 BuiltTool("generate_hiddenapi_lists").
654 FlagWithInput("--csv ", baseFlagsPath).
Paul Duffin537ea3d2021-05-14 10:38:00 +0100655 Input(annotationFlags).
Paul Duffin702210b2021-04-08 20:12:41 +0100656 FlagWithOutput("--output ", tempPath)
657
Paul Duffine3dc6602021-04-14 09:50:43 +0100658 // Add the options for the different categories of flag files.
Paul Duffin524c82c2021-06-09 14:39:28 +0100659 for _, category := range HiddenAPIFlagFileCategories {
Paul Duffin438eb572021-05-21 16:58:23 +0100660 paths := flagFilesByCategory[category]
Paul Duffine3dc6602021-04-14 09:50:43 +0100661 for _, path := range paths {
662 category.commandMutator(command, path)
663 }
Paul Duffin702210b2021-04-08 20:12:41 +0100664 }
665
Paul Duffin32cf58a2021-05-18 16:32:50 +0100666 // If available then pass the automatically generated file containing dex signatures of removed
667 // API members to the rule so they can be marked as removed.
668 if generatedRemovedDexSignatures.Valid() {
669 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path())
670 }
671
Paul Duffin702210b2021-04-08 20:12:41 +0100672 commitChangeForRestat(rule, tempPath, outputPath)
673
Paul Duffindfa10832021-05-13 17:31:51 +0100674 if validFile != nil {
675 // Add the file that indicates that the file generated by this is valid.
676 //
677 // This will cause the validation rule above to be run any time that the output of this rule
678 // changes but the validation will run in parallel with other rules that depend on this file.
679 command.Validation(validFile)
680 }
681
Paul Duffin2fef1362021-04-15 13:32:00 +0100682 rule.Build(name, desc)
683}
684
Paul Duffine5218812021-06-07 13:28:19 +0100685// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the
686// bootclasspath and then encode the flags into the boot dex files.
Paul Duffin2fef1362021-04-15 13:32:00 +0100687//
688// It takes:
689// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind.
690// * The list of modules that are the contents of the fragment.
691// * The additional manually curated flag files to use.
692//
693// It generates:
694// * stub-flags.csv
695// * annotation-flags.csv
696// * metadata.csv
697// * index.csv
698// * all-flags.csv
Paul Duffine5218812021-06-07 13:28:19 +0100699// * encoded boot dex files
700func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput {
Paul Duffin2fef1362021-04-15 13:32:00 +0100701 hiddenApiSubDir := "modular-hiddenapi"
702
Paul Duffine5218812021-06-07 13:28:19 +0100703 // Gather information about the boot dex files for the boot libraries provided by this fragment.
704 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents)
Paul Duffin1352f7c2021-05-21 22:18:49 +0100705
706 // Generate the stub-flags.csv.
Paul Duffin2fef1362021-04-15 13:32:00 +0100707 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv")
Paul Duffine5218812021-06-07 13:28:19 +0100708 rule := ruleToGenerateHiddenAPIStubFlagsFile(ctx, stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input)
Paul Duffin2fef1362021-04-15 13:32:00 +0100709 rule.Build("modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags")
710
Paul Duffin537ea3d2021-05-14 10:38:00 +0100711 // Extract the classes jars from the contents.
Paul Duffindd5993f2021-06-10 10:18:22 +0100712 classesJars := extractClassesJarsFromModules(contents)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100713
Paul Duffin2fef1362021-04-15 13:32:00 +0100714 // Generate the set of flags from the annotations in the source code.
715 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100716 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100717
718 // Generate the metadata from the annotations in the source code.
719 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100720 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100721
Paul Duffin537ea3d2021-05-14 10:38:00 +0100722 // Generate the index file from the CSV files in the classes jars.
Paul Duffin2fef1362021-04-15 13:32:00 +0100723 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv")
Paul Duffin850e61f2021-05-14 09:58:48 +0100724 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV)
Paul Duffin2fef1362021-04-15 13:32:00 +0100725
Paul Duffinaf99afa2021-05-21 22:18:56 +0100726 // 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 +0100727 // containing dex signatures of all the removed APIs. In the monolithic files that is done by
728 // manually combining all the removed.txt files for each API and then converting them to dex
Paul Duffin32cf58a2021-05-18 16:32:50 +0100729 // signatures, see the combined-removed-dex module. This does that automatically by using the
730 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the
731 // stub_libs and contents properties of a bootclasspath_fragment.
732 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles)
Paul Duffin2fef1362021-04-15 13:32:00 +0100733
734 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex
735 // files.
Paul Duffine5218812021-06-07 13:28:19 +0100736 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv")
737 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, annotationFlagsCSV, input.FlagFilesByCategory, nil, removedDexSignatures)
738
739 // Encode the flags into the boot dex files.
740 encodedBootDexJarsByModule := map[string]android.Path{}
741 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath
742 for _, name := range android.SortedStringKeys(bootDexInfoByModule) {
743 bootDexInfo := bootDexInfoByModule[name]
744 unencodedDex := bootDexInfo.path
745 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir)
746 encodedBootDexJarsByModule[name] = encodedDex
747 }
Paul Duffin2fef1362021-04-15 13:32:00 +0100748
749 // Store the paths in the info for use by other modules and sdk snapshot generation.
Paul Duffine5218812021-06-07 13:28:19 +0100750 output := HiddenAPIOutput{
751 HiddenAPIFlagOutput: HiddenAPIFlagOutput{
752 StubFlagsPath: stubFlagsCSV,
753 AnnotationFlagsPath: annotationFlagsCSV,
754 MetadataPath: metadataCSV,
755 IndexPath: indexCSV,
756 AllFlagsPath: allFlagsCSV,
757 },
758 EncodedBootDexFilesByModule: encodedBootDexJarsByModule,
Paul Duffin1e6f5c42021-05-21 16:15:31 +0100759 }
760 return &output
Paul Duffin702210b2021-04-08 20:12:41 +0100761}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100762
Paul Duffin32cf58a2021-05-18 16:32:50 +0100763func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath {
764 if len(removedTxtFiles) == 0 {
765 return android.OptionalPath{}
766 }
767
768 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt")
769
770 rule := android.NewRuleBuilder(pctx, ctx)
771 rule.Command().
772 BuiltTool("metalava").
773 Flag("--no-banner").
774 Inputs(removedTxtFiles).
775 FlagWithOutput("--dex-api ", output)
776 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures")
777 return android.OptionalPathForPath(output)
778}
779
Paul Duffindd5993f2021-06-10 10:18:22 +0100780// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules.
Paul Duffine5218812021-06-07 13:28:19 +0100781func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
782 bootDexJars := bootDexJarByModule{}
Paul Duffin537ea3d2021-05-14 10:38:00 +0100783 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +0100784 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module)
785 if hiddenAPIModule == nil {
786 continue
787 }
Paul Duffine5218812021-06-07 13:28:19 +0100788 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
789 bootDexJars.addPath(module, bootDexJar)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100790 }
791 return bootDexJars
792}
793
Paul Duffindd5993f2021-06-10 10:18:22 +0100794func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule {
795 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
796 return hiddenAPIModule
797 } else if _, ok := module.(*DexImport); ok {
798 // Ignore this for the purposes of hidden API processing
799 } else {
800 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module)
801 }
802
803 return nil
804}
805
Paul Duffine5218812021-06-07 13:28:19 +0100806// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule.
807type bootDexInfo struct {
808 // The path to the dex jar that has not had hidden API flags encoded into it.
809 path android.Path
810
811 // Indicates whether the dex jar needs uncompressing before encoding.
812 uncompressDex bool
813}
814
815// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex
816// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag.
817type bootDexInfoByModule map[string]bootDexInfo
818
819// bootDexJars returns the boot dex jar paths sorted by their keys.
820func (b bootDexInfoByModule) bootDexJars() android.Paths {
821 paths := android.Paths{}
822 for _, m := range android.SortedStringKeys(b) {
823 paths = append(paths, b[m].path)
824 }
825 return paths
826}
827
828// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from
829// each of the supplied modules which must implement hiddenAPIModule.
830func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule {
831 bootDexJarsByModule := bootDexInfoByModule{}
832 for _, module := range contents {
833 hiddenAPIModule := module.(hiddenAPIModule)
834 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule)
835 bootDexJarsByModule[module.Name()] = bootDexInfo{
836 path: bootDexJar,
837 uncompressDex: *hiddenAPIModule.uncompressDex(),
838 }
839 }
840
841 return bootDexJarsByModule
842}
843
844// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule.
845//
846// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that
847// create a fake path and either report an error immediately or defer reporting of the error until
848// the path is actually used.
849func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path {
850 bootDexJar := module.bootDexJar()
851 if bootDexJar == nil {
852 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name()))
853 bootDexJar = fake
854
855 handleMissingDexBootFile(ctx, module, fake)
856 }
857 return bootDexJar
858}
859
Paul Duffindd5993f2021-06-10 10:18:22 +0100860// extractClassesJarsFromModules extracts the class jars from the supplied modules.
861func extractClassesJarsFromModules(contents []android.Module) android.Paths {
Paul Duffin537ea3d2021-05-14 10:38:00 +0100862 classesJars := android.Paths{}
863 for _, module := range contents {
Paul Duffindd5993f2021-06-10 10:18:22 +0100864 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...)
Paul Duffin537ea3d2021-05-14 10:38:00 +0100865 }
866 return classesJars
867}
Paul Duffin5f148ca2021-06-02 17:24:22 +0100868
Paul Duffindd5993f2021-06-10 10:18:22 +0100869// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module.
870func retrieveClassesJarsFromModule(module android.Module) android.Paths {
871 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok {
872 return hiddenAPIModule.classesJars()
873 }
874
875 return nil
876}
877
Paul Duffin5f148ca2021-06-02 17:24:22 +0100878// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by
879// Soong but should instead only be reported in ninja if the file is actually built.
880func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool {
881 // TODO(b/179354495): Remove this workaround when it is unnecessary.
882 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So,
883 // create a fake one that will cause a build error only if it is used.
884 if ctx.Config().AlwaysUsePrebuiltSdks() {
885 return true
886 }
887
Paul Duffine5218812021-06-07 13:28:19 +0100888 // Any missing dependency should be allowed.
889 if ctx.Config().AllowMissingDependencies() {
890 return true
891 }
892
Paul Duffin5f148ca2021-06-02 17:24:22 +0100893 // This is called for both platform_bootclasspath and bootclasspath_fragment modules.
894 //
895 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules.
896 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it
897 // but unfortunately, due to b/187910671 it does.
898 //
899 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module
900 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e.
901 // has an APEX variant not a platform variant.
902 //
903 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot
904 // provide a boot dex jar:
905 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it
906 // does not have an APEX variant and only has a platform variant and neither do its content
907 // modules.
908 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all
909 // java_sdk_library_import modules to be treated as preferred and as many of them are not part
910 // of an apex they cannot provide a boot dex jar.
911 //
912 // The first case causes problems when the affected prebuilt modules are preferred but that is an
913 // invalid configuration and it is ok for it to fail as the work to enable that is not yet
914 // complete. The second case is used for building targets that do not use boot dex jars and so
915 // deferring error reporting to ninja is fine as the affected ninja targets should never be built.
916 // That is handled above.
917 //
918 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike
919 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it
920 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed
921 // that if the library can be part of an APEX then it is the APEX variant that is used.
922 //
923 // This check handles the slightly different requirements of the bootclasspath_fragment and
924 // platform_bootclasspath modules by only deferring error reporting for the platform variant of
925 // a prebuilt modules that has other variants which are part of an APEX.
926 //
927 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily.
928 if android.IsModulePrebuilt(module) {
929 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() {
930 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
931 if apexInfo.IsForPlatform() {
932 return true
933 }
934 }
935 }
936
937 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there
938 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However,
939 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build
940 // failures missing boot dex jars need to be deferred.
941 if android.IsModuleInVersionedSdk(ctx.Module()) {
942 return true
943 }
944
945 return false
946}
947
948// handleMissingDexBootFile will either log a warning or create an error rule to create the fake
949// file depending on the value returned from deferReportingMissingBootDexJar.
950func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) {
951 if deferReportingMissingBootDexJar(ctx, module) {
952 // Create an error rule that pretends to create the output file but will actually fail if it
953 // is run.
954 ctx.Build(pctx, android.BuildParams{
955 Rule: android.ErrorRule,
956 Output: fake,
957 Args: map[string]string{
958 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module),
959 },
960 })
961 } else {
962 ctx.ModuleErrorf("module %s does not provide a dex jar", module)
963 }
964}
965
966// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's
967// DexJarBuildPath() method.
968//
969// The returned path will usually be to a dex jar file that has been encoded with hidden API flags.
970// However, under certain conditions, e.g. errors, or special build configurations it will return
971// a path to a fake file.
972func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path {
973 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath()
974 if bootDexJar == nil {
975 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name()))
976 bootDexJar = fake
977
978 handleMissingDexBootFile(ctx, module, fake)
979 }
980 return bootDexJar
981}
982
983// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules.
984func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule {
985 encodedDexJarsByModuleName := bootDexJarByModule{}
986 for _, module := range contents {
987 path := retrieveEncodedBootDexJarFromModule(ctx, module)
988 encodedDexJarsByModuleName.addPath(module, path)
989 }
990 return encodedDexJarsByModuleName
991}