1// 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 ( 18 "fmt" 19 "strings" 20 21 "android/soong/android" 22 "github.com/google/blueprint" 23) 24 25// Contains support for processing hiddenAPI in a modular fashion. 26 27// HiddenAPIScope encapsulates all the information that the hidden API processing needs about API 28// scopes, i.e. what is called android.SdkKind and apiScope. It does not just use those as they do 29// not provide the information needed by hidden API processing. 30type HiddenAPIScope struct { 31 // The name of the scope, used for debug purposes. 32 name string 33 34 // The corresponding android.SdkKind, used for retrieving paths from java_sdk_library* modules. 35 sdkKind android.SdkKind 36 37 // The option needed to passed to "hiddenapi list". 38 hiddenAPIListOption string 39 40 // The name sof the source stub library modules that contain the API provided by the platform, 41 // i.e. by modules that are not in an APEX. 42 nonUpdatableSourceModule string 43 44 // The names of the prebuilt stub library modules that contain the API provided by the platform, 45 // i.e. by modules that are not in an APEX. 46 nonUpdatablePrebuiltModule string 47} 48 49// initHiddenAPIScope initializes the scope. 50func initHiddenAPIScope(apiScope *HiddenAPIScope) *HiddenAPIScope { 51 sdkKind := apiScope.sdkKind 52 // The platform does not provide a core platform API. 53 if sdkKind != android.SdkCorePlatform { 54 kindAsString := sdkKind.String() 55 var insert string 56 if sdkKind == android.SdkPublic { 57 insert = "" 58 } else { 59 insert = "." + strings.ReplaceAll(kindAsString, "-", "_") 60 } 61 62 nonUpdatableModule := "android-non-updatable" 63 64 // Construct the name of the android-non-updatable source module for this scope. 65 apiScope.nonUpdatableSourceModule = fmt.Sprintf("%s.stubs%s", nonUpdatableModule, insert) 66 67 prebuiltModuleName := func(name string, kind string) string { 68 return fmt.Sprintf("sdk_%s_current_%s", kind, name) 69 } 70 71 // Construct the name of the android-non-updatable prebuilt module for this scope. 72 apiScope.nonUpdatablePrebuiltModule = prebuiltModuleName(nonUpdatableModule, kindAsString) 73 } 74 75 return apiScope 76} 77 78// android-non-updatable takes the name of a module and returns a possibly scope specific name of 79// the module. 80func (l *HiddenAPIScope) scopeSpecificStubModule(ctx android.BaseModuleContext, name string) string { 81 // The android-non-updatable is not a java_sdk_library but there are separate stub libraries for 82 // each scope. 83 // TODO(b/192067200): Remove special handling of android-non-updatable. 84 if name == "android-non-updatable" { 85 if ctx.Config().AlwaysUsePrebuiltSdks() { 86 return l.nonUpdatablePrebuiltModule 87 } else { 88 return l.nonUpdatableSourceModule 89 } 90 } else { 91 // Assume that the module is either a java_sdk_library (or equivalent) and so will provide 92 // separate stub jars for each scope or is a java_library (or equivalent) in which case it will 93 // have the same stub jar for each scope. 94 return name 95 } 96} 97 98func (l *HiddenAPIScope) String() string { 99 return fmt.Sprintf("HiddenAPIScope{%s}", l.name) 100} 101 102var ( 103 PublicHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ 104 name: "public", 105 sdkKind: android.SdkPublic, 106 hiddenAPIListOption: "--public-stub-classpath", 107 }) 108 SystemHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ 109 name: "system", 110 sdkKind: android.SdkSystem, 111 hiddenAPIListOption: "--system-stub-classpath", 112 }) 113 TestHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ 114 name: "test", 115 sdkKind: android.SdkTest, 116 hiddenAPIListOption: "--test-stub-classpath", 117 }) 118 ModuleLibHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ 119 name: "module-lib", 120 sdkKind: android.SdkModule, 121 }) 122 CorePlatformHiddenAPIScope = initHiddenAPIScope(&HiddenAPIScope{ 123 name: "core-platform", 124 sdkKind: android.SdkCorePlatform, 125 hiddenAPIListOption: "--core-platform-stub-classpath", 126 }) 127 128 // hiddenAPIRelevantSdkKinds lists all the android.SdkKind instances that are needed by the hidden 129 // API processing. 130 // 131 // These are roughly in order from narrowest API surface to widest. Widest means the API stubs 132 // with the biggest API surface, e.g. test is wider than system is wider than public. 133 // 134 // Core platform is considered wider than system/module-lib because those modules that provide 135 // core platform APIs either do not have any system/module-lib APIs at all, or if they do it is 136 // because the core platform API is being converted to system/module-lib APIs. In either case the 137 // system/module-lib APIs are subsets of the core platform API. 138 // 139 // This is not strictly in order from narrowest to widest as the Test API is wider than system but 140 // is neither wider or narrower than the module-lib or core platform APIs. However, this works 141 // well enough at the moment. 142 // TODO(b/191644675): Correctly reflect the sub/superset relationships between APIs. 143 hiddenAPIScopes = []*HiddenAPIScope{ 144 PublicHiddenAPIScope, 145 SystemHiddenAPIScope, 146 TestHiddenAPIScope, 147 ModuleLibHiddenAPIScope, 148 CorePlatformHiddenAPIScope, 149 } 150 151 // The HiddenAPIScope instances that are supported by a java_sdk_library. 152 // 153 // CorePlatformHiddenAPIScope is not used as the java_sdk_library does not have special support 154 // for core_platform API, instead it is implemented as a customized form of PublicHiddenAPIScope. 155 hiddenAPISdkLibrarySupportedScopes = []*HiddenAPIScope{ 156 PublicHiddenAPIScope, 157 SystemHiddenAPIScope, 158 TestHiddenAPIScope, 159 ModuleLibHiddenAPIScope, 160 } 161 162 // The HiddenAPIScope instances that are supported by the `hiddenapi list`. 163 hiddenAPIFlagScopes = []*HiddenAPIScope{ 164 PublicHiddenAPIScope, 165 SystemHiddenAPIScope, 166 TestHiddenAPIScope, 167 CorePlatformHiddenAPIScope, 168 } 169) 170 171type hiddenAPIStubsDependencyTag struct { 172 blueprint.BaseDependencyTag 173 174 // The api scope for which this dependency was added. 175 apiScope *HiddenAPIScope 176 177 // Indicates that the dependency is not for an API provided by the current bootclasspath fragment 178 // but is an additional API provided by a module that is not part of the current bootclasspath 179 // fragment. 180 fromAdditionalDependency bool 181} 182 183func (b hiddenAPIStubsDependencyTag) ExcludeFromApexContents() { 184} 185 186func (b hiddenAPIStubsDependencyTag) ReplaceSourceWithPrebuilt() bool { 187 return false 188} 189 190func (b hiddenAPIStubsDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { 191 // Do not add additional dependencies to the sdk. 192 if b.fromAdditionalDependency { 193 return nil 194 } 195 196 // If the module is a java_sdk_library then treat it as if it was specific in the java_sdk_libs 197 // property, otherwise treat if it was specified in the java_header_libs property. 198 if javaSdkLibrarySdkMemberType.IsInstance(child) { 199 return javaSdkLibrarySdkMemberType 200 } 201 202 return javaHeaderLibsSdkMemberType 203} 204 205func (b hiddenAPIStubsDependencyTag) ExportMember() bool { 206 // Export the module added via this dependency tag from the sdk. 207 return true 208} 209 210// Avoid having to make stubs content explicitly visible to dependent modules. 211// 212// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules 213// with proper dependencies. 214// TODO(b/177892522): Remove this and add needed visibility. 215func (b hiddenAPIStubsDependencyTag) ExcludeFromVisibilityEnforcement() { 216} 217 218var _ android.ExcludeFromVisibilityEnforcementTag = hiddenAPIStubsDependencyTag{} 219var _ android.ReplaceSourceWithPrebuilt = hiddenAPIStubsDependencyTag{} 220var _ android.ExcludeFromApexContentsTag = hiddenAPIStubsDependencyTag{} 221var _ android.SdkMemberTypeDependencyTag = hiddenAPIStubsDependencyTag{} 222 223// hiddenAPIComputeMonolithicStubLibModules computes the set of module names that provide stubs 224// needed to produce the hidden API monolithic stub flags file. 225func hiddenAPIComputeMonolithicStubLibModules(config android.Config) map[*HiddenAPIScope][]string { 226 var publicStubModules []string 227 var systemStubModules []string 228 var testStubModules []string 229 var corePlatformStubModules []string 230 231 if config.AlwaysUsePrebuiltSdks() { 232 // Build configuration mandates using prebuilt stub modules 233 publicStubModules = append(publicStubModules, "sdk_public_current_android") 234 systemStubModules = append(systemStubModules, "sdk_system_current_android") 235 testStubModules = append(testStubModules, "sdk_test_current_android") 236 } else { 237 // Use stub modules built from source 238 publicStubModules = append(publicStubModules, "android_stubs_current") 239 systemStubModules = append(systemStubModules, "android_system_stubs_current") 240 testStubModules = append(testStubModules, "android_test_stubs_current") 241 } 242 // We do not have prebuilts of the core platform api yet 243 corePlatformStubModules = append(corePlatformStubModules, "legacy.core.platform.api.stubs") 244 245 // Allow products to define their own stubs for custom product jars that apps can use. 246 publicStubModules = append(publicStubModules, config.ProductHiddenAPIStubs()...) 247 systemStubModules = append(systemStubModules, config.ProductHiddenAPIStubsSystem()...) 248 testStubModules = append(testStubModules, config.ProductHiddenAPIStubsTest()...) 249 if config.IsEnvTrue("EMMA_INSTRUMENT") { 250 // Add jacoco-stubs to public, system and test. It doesn't make any real difference as public 251 // allows everyone access but it is needed to ensure consistent flags between the 252 // bootclasspath fragment generated flags and the platform_bootclasspath generated flags. 253 publicStubModules = append(publicStubModules, "jacoco-stubs") 254 systemStubModules = append(systemStubModules, "jacoco-stubs") 255 testStubModules = append(testStubModules, "jacoco-stubs") 256 } 257 258 m := map[*HiddenAPIScope][]string{} 259 m[PublicHiddenAPIScope] = publicStubModules 260 m[SystemHiddenAPIScope] = systemStubModules 261 m[TestHiddenAPIScope] = testStubModules 262 m[CorePlatformHiddenAPIScope] = corePlatformStubModules 263 return m 264} 265 266// hiddenAPIAddStubLibDependencies adds dependencies onto the modules specified in 267// apiScopeToStubLibModules. It adds them in a well known order and uses a HiddenAPIScope specific 268// tag to identify the source of the dependency. 269func hiddenAPIAddStubLibDependencies(ctx android.BottomUpMutatorContext, apiScopeToStubLibModules map[*HiddenAPIScope][]string) { 270 module := ctx.Module() 271 for _, apiScope := range hiddenAPIScopes { 272 modules := apiScopeToStubLibModules[apiScope] 273 ctx.AddDependency(module, hiddenAPIStubsDependencyTag{apiScope: apiScope}, modules...) 274 } 275} 276 277// hiddenAPIRetrieveDexJarBuildPath retrieves the DexJarBuildPath from the specified module, if 278// available, or reports an error. 279func hiddenAPIRetrieveDexJarBuildPath(ctx android.ModuleContext, module android.Module, kind android.SdkKind) android.Path { 280 var dexJar android.Path 281 if sdkLibrary, ok := module.(SdkLibraryDependency); ok { 282 dexJar = sdkLibrary.SdkApiStubDexJar(ctx, kind) 283 } else if j, ok := module.(UsesLibraryDependency); ok { 284 dexJar = j.DexJarBuildPath() 285 } else { 286 ctx.ModuleErrorf("dependency %s of module type %s does not support providing a dex jar", module, ctx.OtherModuleType(module)) 287 return nil 288 } 289 290 if dexJar == nil { 291 ctx.ModuleErrorf("dependency %s does not provide a dex jar, consider setting compile_dex: true", module) 292 } 293 return dexJar 294} 295 296// buildRuleToGenerateHiddenAPIStubFlagsFile creates a rule to create a hidden API stub flags file. 297// 298// The rule is initialized but not built so that the caller can modify it and select an appropriate 299// name. 300func buildRuleToGenerateHiddenAPIStubFlagsFile(ctx android.BuilderContext, name, desc string, outputPath android.WritablePath, bootDexJars android.Paths, input HiddenAPIFlagInput, moduleStubFlagsPaths android.Paths) { 301 // Singleton rule which applies hiddenapi on all boot class path dex files. 302 rule := android.NewRuleBuilder(pctx, ctx) 303 304 tempPath := tempPathForRestat(ctx, outputPath) 305 306 // Find the widest API stubs provided by the fragments on which this depends, if any. 307 dependencyStubDexJars := input.DependencyStubDexJarsByScope.StubDexJarsForWidestAPIScope() 308 309 // Add widest API stubs from the additional dependencies of this, if any. 310 dependencyStubDexJars = append(dependencyStubDexJars, input.AdditionalStubDexJarsByScope.StubDexJarsForWidestAPIScope()...) 311 312 command := rule.Command(). 313 Tool(ctx.Config().HostToolPath(ctx, "hiddenapi")). 314 Text("list"). 315 FlagForEachInput("--dependency-stub-dex=", dependencyStubDexJars). 316 FlagForEachInput("--boot-dex=", bootDexJars) 317 318 // If no module stub flags paths are provided then this must be being called for a 319 // bootclasspath_fragment and not the whole platform_bootclasspath. 320 if moduleStubFlagsPaths == nil { 321 // This is being run on a fragment of the bootclasspath. 322 command.Flag("--fragment") 323 } 324 325 // Iterate over the api scopes in a fixed order. 326 for _, apiScope := range hiddenAPIFlagScopes { 327 // Merge in the stub dex jar paths for this api scope from the fragments on which it depends. 328 // They will be needed to resolve dependencies from this fragment's stubs to classes in the 329 // other fragment's APIs. 330 var paths android.Paths 331 paths = append(paths, input.DependencyStubDexJarsByScope.StubDexJarsForScope(apiScope)...) 332 paths = append(paths, input.AdditionalStubDexJarsByScope.StubDexJarsForScope(apiScope)...) 333 paths = append(paths, input.StubDexJarsByScope.StubDexJarsForScope(apiScope)...) 334 if len(paths) > 0 { 335 option := apiScope.hiddenAPIListOption 336 command.FlagWithInputList(option+"=", paths, ":") 337 } 338 } 339 340 // Add the output path. 341 command.FlagWithOutput("--out-api-flags=", tempPath) 342 343 // If there are stub flag files that have been generated by fragments on which this depends then 344 // use them to validate the stub flag file generated by the rules created by this method. 345 if len(moduleStubFlagsPaths) > 0 { 346 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, moduleStubFlagsPaths) 347 348 // Add the file that indicates that the file generated by this is valid. 349 // 350 // This will cause the validation rule above to be run any time that the output of this rule 351 // changes but the validation will run in parallel with other rules that depend on this file. 352 command.Validation(validFile) 353 } 354 355 commitChangeForRestat(rule, tempPath, outputPath) 356 357 rule.Build(name, desc) 358} 359 360// HiddenAPIFlagFileProperties contains paths to the flag files that can be used to augment the 361// information obtained from annotations within the source code in order to create the complete set 362// of flags that should be applied to the dex implementation jars on the bootclasspath. 363// 364// Each property contains a list of paths. With the exception of the Unsupported_packages the paths 365// of each property reference a plain text file that contains a java signature per line. The flags 366// for each of those signatures will be updated in a property specific way. 367// 368// The Unsupported_packages property contains a list of paths, each of which is a plain text file 369// with one Java package per line. All members of all classes within that package (but not nested 370// packages) will be updated in a property specific way. 371type HiddenAPIFlagFileProperties struct { 372 // Marks each signature in the referenced files as being unsupported. 373 Unsupported []string `android:"path"` 374 375 // Marks each signature in the referenced files as being unsupported because it has been removed. 376 // Any conflicts with other flags are ignored. 377 Removed []string `android:"path"` 378 379 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= R 380 // and low priority. 381 Max_target_r_low_priority []string `android:"path"` 382 383 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= Q. 384 Max_target_q []string `android:"path"` 385 386 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= P. 387 Max_target_p []string `android:"path"` 388 389 // Marks each signature in the referenced files as being supported only for targetSdkVersion <= O 390 // and low priority. Any conflicts with other flags are ignored. 391 Max_target_o_low_priority []string `android:"path"` 392 393 // Marks each signature in the referenced files as being blocked. 394 Blocked []string `android:"path"` 395 396 // Marks each signature in every package in the referenced files as being unsupported. 397 Unsupported_packages []string `android:"path"` 398} 399 400type hiddenAPIFlagFileCategory struct { 401 // PropertyName is the name of the property for this category. 402 PropertyName string 403 404 // propertyValueReader retrieves the value of the property for this category from the set of 405 // properties. 406 propertyValueReader func(properties *HiddenAPIFlagFileProperties) []string 407 408 // commandMutator adds the appropriate command line options for this category to the supplied 409 // command 410 commandMutator func(command *android.RuleBuilderCommand, path android.Path) 411} 412 413// The flag file category for removed members of the API. 414// 415// This is extracted from HiddenAPIFlagFileCategories as it is needed to add the dex signatures 416// list of removed API members that are generated automatically from the removed.txt files provided 417// by API stubs. 418var hiddenAPIRemovedFlagFileCategory = &hiddenAPIFlagFileCategory{ 419 // See HiddenAPIFlagFileProperties.Removed 420 PropertyName: "removed", 421 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 422 return properties.Removed 423 }, 424 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 425 command.FlagWithInput("--unsupported ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "removed") 426 }, 427} 428 429var HiddenAPIFlagFileCategories = []*hiddenAPIFlagFileCategory{ 430 // See HiddenAPIFlagFileProperties.Unsupported 431 { 432 PropertyName: "unsupported", 433 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 434 return properties.Unsupported 435 }, 436 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 437 command.FlagWithInput("--unsupported ", path) 438 }, 439 }, 440 hiddenAPIRemovedFlagFileCategory, 441 // See HiddenAPIFlagFileProperties.Max_target_r_low_priority 442 { 443 PropertyName: "max_target_r_low_priority", 444 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 445 return properties.Max_target_r_low_priority 446 }, 447 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 448 command.FlagWithInput("--max-target-r ", path).FlagWithArg("--tag ", "lo-prio") 449 }, 450 }, 451 // See HiddenAPIFlagFileProperties.Max_target_q 452 { 453 PropertyName: "max_target_q", 454 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 455 return properties.Max_target_q 456 }, 457 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 458 command.FlagWithInput("--max-target-q ", path) 459 }, 460 }, 461 // See HiddenAPIFlagFileProperties.Max_target_p 462 { 463 PropertyName: "max_target_p", 464 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 465 return properties.Max_target_p 466 }, 467 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 468 command.FlagWithInput("--max-target-p ", path) 469 }, 470 }, 471 // See HiddenAPIFlagFileProperties.Max_target_o_low_priority 472 { 473 PropertyName: "max_target_o_low_priority", 474 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 475 return properties.Max_target_o_low_priority 476 }, 477 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 478 command.FlagWithInput("--max-target-o ", path).Flag("--ignore-conflicts ").FlagWithArg("--tag ", "lo-prio") 479 }, 480 }, 481 // See HiddenAPIFlagFileProperties.Blocked 482 { 483 PropertyName: "blocked", 484 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 485 return properties.Blocked 486 }, 487 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 488 command.FlagWithInput("--blocked ", path) 489 }, 490 }, 491 // See HiddenAPIFlagFileProperties.Unsupported_packages 492 { 493 PropertyName: "unsupported_packages", 494 propertyValueReader: func(properties *HiddenAPIFlagFileProperties) []string { 495 return properties.Unsupported_packages 496 }, 497 commandMutator: func(command *android.RuleBuilderCommand, path android.Path) { 498 command.FlagWithInput("--unsupported ", path).Flag("--packages ") 499 }, 500 }, 501} 502 503// FlagFilesByCategory maps a hiddenAPIFlagFileCategory to the paths to the files in that category. 504type FlagFilesByCategory map[*hiddenAPIFlagFileCategory]android.Paths 505 506// append appends the supplied flags files to the corresponding category in this map. 507func (s FlagFilesByCategory) append(other FlagFilesByCategory) { 508 for _, category := range HiddenAPIFlagFileCategories { 509 s[category] = append(s[category], other[category]...) 510 } 511} 512 513// dedup removes duplicates in the flag files, while maintaining the order in which they were 514// appended. 515func (s FlagFilesByCategory) dedup() { 516 for category, paths := range s { 517 s[category] = android.FirstUniquePaths(paths) 518 } 519} 520 521// HiddenAPIInfo contains information provided by the hidden API processing. 522// 523// That includes paths resolved from HiddenAPIFlagFileProperties and also generated by hidden API 524// processing. 525type HiddenAPIInfo struct { 526 // FlagFilesByCategory maps from the flag file category to the paths containing information for 527 // that category. 528 FlagFilesByCategory FlagFilesByCategory 529 530 // The paths to the stub dex jars for each of the *HiddenAPIScope in hiddenAPIScopes provided by 531 // this fragment and the fragments on which this depends. 532 TransitiveStubDexJarsByScope StubDexJarsByModule 533 534 // The output from the hidden API processing needs to be made available to other modules. 535 HiddenAPIFlagOutput 536} 537 538func newHiddenAPIInfo() *HiddenAPIInfo { 539 info := HiddenAPIInfo{ 540 FlagFilesByCategory: FlagFilesByCategory{}, 541 TransitiveStubDexJarsByScope: StubDexJarsByModule{}, 542 } 543 return &info 544} 545 546func (i *HiddenAPIInfo) mergeFromFragmentDeps(ctx android.ModuleContext, fragments []android.Module) { 547 // Merge all the information from the fragments. The fragments form a DAG so it is possible that 548 // this will introduce duplicates so they will be resolved after processing all the fragments. 549 for _, fragment := range fragments { 550 if ctx.OtherModuleHasProvider(fragment, HiddenAPIInfoProvider) { 551 info := ctx.OtherModuleProvider(fragment, HiddenAPIInfoProvider).(HiddenAPIInfo) 552 i.TransitiveStubDexJarsByScope.addStubDexJarsByModule(info.TransitiveStubDexJarsByScope) 553 } 554 } 555} 556 557var HiddenAPIInfoProvider = blueprint.NewProvider(HiddenAPIInfo{}) 558 559// ModuleStubDexJars contains the stub dex jars provided by a single module. 560// 561// It maps a *HiddenAPIScope to the path to stub dex jars appropriate for that scope. See 562// hiddenAPIScopes for a list of the acceptable *HiddenAPIScope values. 563type ModuleStubDexJars map[*HiddenAPIScope]android.Path 564 565// stubDexJarForWidestAPIScope returns the stub dex jars for the widest API scope provided by this 566// map. 567// 568// The relative width of APIs is determined by their order in hiddenAPIScopes. 569func (s ModuleStubDexJars) stubDexJarForWidestAPIScope() android.Path { 570 for i := len(hiddenAPIScopes) - 1; i >= 0; i-- { 571 apiScope := hiddenAPIScopes[i] 572 if stubsForAPIScope, ok := s[apiScope]; ok { 573 return stubsForAPIScope 574 } 575 } 576 577 return nil 578} 579 580// StubDexJarsByModule contains the stub dex jars provided by a set of modules. 581// 582// It maps a module name to the path to the stub dex jars provided by that module. 583type StubDexJarsByModule map[string]ModuleStubDexJars 584 585// addStubDexJar adds a stub dex jar path provided by the specified module for the specified scope. 586func (s StubDexJarsByModule) addStubDexJar(ctx android.ModuleContext, module android.Module, scope *HiddenAPIScope, stubDexJar android.Path) { 587 name := android.RemoveOptionalPrebuiltPrefix(module.Name()) 588 589 // Each named module provides one dex jar for each scope. However, in some cases different API 590 // versions of a single classes are provided by separate modules. e.g. the core platform 591 // version of java.lang.Object is provided by the legacy.art.module.platform.api module but the 592 // public version is provided by the art.module.public.api module. In those cases it is necessary 593 // to treat all those modules as they were the same name, otherwise it will result in multiple 594 // definitions of a single class being passed to hidden API processing which will cause an error. 595 if name == scope.nonUpdatablePrebuiltModule || name == scope.nonUpdatableSourceModule { 596 // Treat all *android-non-updatable* modules as if they were part of an android-non-updatable 597 // java_sdk_library. 598 // TODO(b/192067200): Remove once android-non-updatable is a java_sdk_library or equivalent. 599 name = "android-non-updatable" 600 } else if name == "legacy.art.module.platform.api" { 601 // Treat legacy.art.module.platform.api as if it was an API scope provided by the 602 // art.module.public.api java_sdk_library which will be the case once the former has been 603 // migrated to a module_lib API. 604 name = "art.module.public.api" 605 } else if name == "legacy.i18n.module.platform.api" { 606 // Treat legacy.i18n.module.platform.api as if it was an API scope provided by the 607 // i18n.module.public.api java_sdk_library which will be the case once the former has been 608 // migrated to a module_lib API. 609 name = "i18n.module.public.api" 610 } else if name == "conscrypt.module.platform.api" { 611 // Treat conscrypt.module.platform.api as if it was an API scope provided by the 612 // conscrypt.module.public.api java_sdk_library which will be the case once the former has been 613 // migrated to a module_lib API. 614 name = "conscrypt.module.public.api" 615 } else if d, ok := module.(SdkLibraryComponentDependency); ok { 616 sdkLibraryName := d.SdkLibraryName() 617 if sdkLibraryName != nil { 618 // The module is a component of a java_sdk_library so use the name of the java_sdk_library. 619 // e.g. if this module is `foo.system.stubs` and is part of the `foo` java_sdk_library then 620 // use `foo` as the name. 621 name = *sdkLibraryName 622 } 623 } 624 stubDexJarsByScope := s[name] 625 if stubDexJarsByScope == nil { 626 stubDexJarsByScope = ModuleStubDexJars{} 627 s[name] = stubDexJarsByScope 628 } 629 stubDexJarsByScope[scope] = stubDexJar 630} 631 632// addStubDexJarsByModule adds the stub dex jars in the supplied StubDexJarsByModule to this map. 633func (s StubDexJarsByModule) addStubDexJarsByModule(other StubDexJarsByModule) { 634 for module, stubDexJarsByScope := range other { 635 s[module] = stubDexJarsByScope 636 } 637} 638 639// StubDexJarsForWidestAPIScope returns a list of stub dex jars containing the widest API scope 640// provided by each module. 641// 642// The relative width of APIs is determined by their order in hiddenAPIScopes. 643func (s StubDexJarsByModule) StubDexJarsForWidestAPIScope() android.Paths { 644 stubDexJars := android.Paths{} 645 modules := android.SortedStringKeys(s) 646 for _, module := range modules { 647 stubDexJarsByScope := s[module] 648 649 stubDexJars = append(stubDexJars, stubDexJarsByScope.stubDexJarForWidestAPIScope()) 650 } 651 652 return stubDexJars 653} 654 655// StubDexJarsForScope returns a list of stub dex jars containing the stub dex jars provided by each 656// module for the specified scope. 657// 658// If a module does not provide a stub dex jar for the supplied scope then it does not contribute to 659// the returned list. 660func (s StubDexJarsByModule) StubDexJarsForScope(scope *HiddenAPIScope) android.Paths { 661 stubDexJars := android.Paths{} 662 modules := android.SortedStringKeys(s) 663 for _, module := range modules { 664 stubDexJarsByScope := s[module] 665 // Not every module will have the same set of 666 if jars, ok := stubDexJarsByScope[scope]; ok { 667 stubDexJars = append(stubDexJars, jars) 668 } 669 } 670 671 return stubDexJars 672} 673 674// HiddenAPIFlagInput encapsulates information obtained from a module and its dependencies that are 675// needed for hidden API flag generation. 676type HiddenAPIFlagInput struct { 677 // FlagFilesByCategory contains the flag files that override the initial flags that are derived 678 // from the stub dex files. 679 FlagFilesByCategory FlagFilesByCategory 680 681 // StubDexJarsByScope contains the stub dex jars for different *HiddenAPIScope and which determine 682 // the initial flags for each dex member. 683 StubDexJarsByScope StubDexJarsByModule 684 685 // DependencyStubDexJarsByScope contains the stub dex jars provided by the fragments on which this 686 // depends. It is the result of merging HiddenAPIInfo.TransitiveStubDexJarsByScope from each 687 // fragment on which this depends. 688 DependencyStubDexJarsByScope StubDexJarsByModule 689 690 // AdditionalStubDexJarsByScope contains stub dex jars provided by other modules in addition to 691 // the ones that are obtained from fragments on which this depends. 692 // 693 // These are kept separate from stub dex jars in HiddenAPIFlagInput.DependencyStubDexJarsByScope 694 // as there are not propagated transitively to other fragments that depend on this. 695 AdditionalStubDexJarsByScope StubDexJarsByModule 696 697 // RemovedTxtFiles is the list of removed.txt files provided by java_sdk_library modules that are 698 // specified in the bootclasspath_fragment's stub_libs and contents properties. 699 RemovedTxtFiles android.Paths 700} 701 702// newHiddenAPIFlagInput creates a new initialize HiddenAPIFlagInput struct. 703func newHiddenAPIFlagInput() HiddenAPIFlagInput { 704 input := HiddenAPIFlagInput{ 705 FlagFilesByCategory: FlagFilesByCategory{}, 706 StubDexJarsByScope: StubDexJarsByModule{}, 707 DependencyStubDexJarsByScope: StubDexJarsByModule{}, 708 AdditionalStubDexJarsByScope: StubDexJarsByModule{}, 709 } 710 711 return input 712} 713 714// gatherStubLibInfo gathers information from the stub libs needed by hidden API processing from the 715// dependencies added in hiddenAPIAddStubLibDependencies. 716// 717// That includes paths to the stub dex jars as well as paths to the *removed.txt files. 718func (i *HiddenAPIFlagInput) gatherStubLibInfo(ctx android.ModuleContext, contents []android.Module) { 719 addFromModule := func(ctx android.ModuleContext, module android.Module, apiScope *HiddenAPIScope) { 720 sdkKind := apiScope.sdkKind 721 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, sdkKind) 722 if dexJar != nil { 723 i.StubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar) 724 } 725 726 if sdkLibrary, ok := module.(SdkLibraryDependency); ok { 727 removedTxtFile := sdkLibrary.SdkRemovedTxtFile(ctx, sdkKind) 728 i.RemovedTxtFiles = append(i.RemovedTxtFiles, removedTxtFile.AsPaths()...) 729 } 730 } 731 732 // If the contents includes any java_sdk_library modules then add them to the stubs. 733 for _, module := range contents { 734 if _, ok := module.(SdkLibraryDependency); ok { 735 // Add information for every possible API scope needed by hidden API. 736 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes { 737 addFromModule(ctx, module, apiScope) 738 } 739 } 740 } 741 742 ctx.VisitDirectDeps(func(module android.Module) { 743 tag := ctx.OtherModuleDependencyTag(module) 744 if hiddenAPIStubsTag, ok := tag.(hiddenAPIStubsDependencyTag); ok { 745 apiScope := hiddenAPIStubsTag.apiScope 746 if hiddenAPIStubsTag.fromAdditionalDependency { 747 dexJar := hiddenAPIRetrieveDexJarBuildPath(ctx, module, apiScope.sdkKind) 748 if dexJar != nil { 749 i.AdditionalStubDexJarsByScope.addStubDexJar(ctx, module, apiScope, dexJar) 750 } 751 } else { 752 addFromModule(ctx, module, apiScope) 753 } 754 } 755 }) 756 757 // Normalize the paths, i.e. remove duplicates and sort. 758 i.RemovedTxtFiles = android.SortedUniquePaths(i.RemovedTxtFiles) 759} 760 761// extractFlagFilesFromProperties extracts the paths to flag files that are specified in the 762// supplied properties and stores them in this struct. 763func (i *HiddenAPIFlagInput) extractFlagFilesFromProperties(ctx android.ModuleContext, p *HiddenAPIFlagFileProperties) { 764 for _, category := range HiddenAPIFlagFileCategories { 765 paths := android.PathsForModuleSrc(ctx, category.propertyValueReader(p)) 766 i.FlagFilesByCategory[category] = paths 767 } 768} 769 770func (i *HiddenAPIFlagInput) transitiveStubDexJarsByScope() StubDexJarsByModule { 771 transitive := i.DependencyStubDexJarsByScope 772 transitive.addStubDexJarsByModule(i.StubDexJarsByScope) 773 return transitive 774} 775 776// HiddenAPIFlagOutput contains paths to output files from the hidden API flag generation for a 777// bootclasspath_fragment module. 778type HiddenAPIFlagOutput struct { 779 // The path to the generated stub-flags.csv file. 780 StubFlagsPath android.Path 781 782 // The path to the generated annotation-flags.csv file. 783 AnnotationFlagsPath android.Path 784 785 // The path to the generated metadata.csv file. 786 MetadataPath android.Path 787 788 // The path to the generated index.csv file. 789 IndexPath android.Path 790 791 // The path to the generated all-flags.csv file. 792 AllFlagsPath android.Path 793} 794 795// bootDexJarByModule is a map from base module name (without prebuilt_ prefix) to the boot dex 796// path. 797type bootDexJarByModule map[string]android.Path 798 799// addPath adds the path for a module to the map. 800func (b bootDexJarByModule) addPath(module android.Module, path android.Path) { 801 b[android.RemoveOptionalPrebuiltPrefix(module.Name())] = path 802} 803 804// bootDexJars returns the boot dex jar paths sorted by their keys. 805func (b bootDexJarByModule) bootDexJars() android.Paths { 806 paths := android.Paths{} 807 for _, k := range android.SortedStringKeys(b) { 808 paths = append(paths, b[k]) 809 } 810 return paths 811} 812 813// bootDexJarsWithoutCoverage returns the boot dex jar paths sorted by their keys without coverage 814// libraries if present. 815func (b bootDexJarByModule) bootDexJarsWithoutCoverage() android.Paths { 816 paths := android.Paths{} 817 for _, k := range android.SortedStringKeys(b) { 818 if k == "jacocoagent" { 819 continue 820 } 821 paths = append(paths, b[k]) 822 } 823 return paths 824} 825 826// HiddenAPIOutput encapsulates the output from the hidden API processing. 827type HiddenAPIOutput struct { 828 HiddenAPIFlagOutput 829 830 // The map from base module name to the path to the encoded boot dex file. 831 EncodedBootDexFilesByModule bootDexJarByModule 832} 833 834// pathForValidation creates a path of the same type as the supplied type but with a name of 835// <path>.valid. 836// 837// e.g. If path is an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv then this will return 838// an OutputPath for out/soong/hiddenapi/hiddenapi-flags.csv.valid 839func pathForValidation(ctx android.PathContext, path android.WritablePath) android.WritablePath { 840 extWithoutLeadingDot := strings.TrimPrefix(path.Ext(), ".") 841 return path.ReplaceExtension(ctx, extWithoutLeadingDot+".valid") 842} 843 844// buildRuleToGenerateHiddenApiFlags creates a rule to create the monolithic hidden API flags from 845// the flags from all the modules, the stub flags, augmented with some additional configuration 846// files. 847// 848// baseFlagsPath is the path to the flags file containing all the information from the stubs plus 849// an entry for every single member in the dex implementation jars of the individual modules. Every 850// signature in any of the other files MUST be included in this file. 851// 852// annotationFlags is the path to the annotation flags file generated from annotation information 853// in each module. 854// 855// hiddenAPIInfo is a struct containing paths to files that augment the information provided by 856// the annotationFlags. 857func buildRuleToGenerateHiddenApiFlags(ctx android.BuilderContext, name, desc string, 858 outputPath android.WritablePath, baseFlagsPath android.Path, annotationFlagPaths android.Paths, 859 flagFilesByCategory FlagFilesByCategory, allFlagsPaths android.Paths, generatedRemovedDexSignatures android.OptionalPath) { 860 861 // Create the rule that will generate the flag files. 862 tempPath := tempPathForRestat(ctx, outputPath) 863 rule := android.NewRuleBuilder(pctx, ctx) 864 command := rule.Command(). 865 BuiltTool("generate_hiddenapi_lists"). 866 FlagWithInput("--csv ", baseFlagsPath). 867 Inputs(annotationFlagPaths). 868 FlagWithOutput("--output ", tempPath) 869 870 // Add the options for the different categories of flag files. 871 for _, category := range HiddenAPIFlagFileCategories { 872 paths := flagFilesByCategory[category] 873 for _, path := range paths { 874 category.commandMutator(command, path) 875 } 876 } 877 878 // If available then pass the automatically generated file containing dex signatures of removed 879 // API members to the rule so they can be marked as removed. 880 if generatedRemovedDexSignatures.Valid() { 881 hiddenAPIRemovedFlagFileCategory.commandMutator(command, generatedRemovedDexSignatures.Path()) 882 } 883 884 commitChangeForRestat(rule, tempPath, outputPath) 885 886 // If there are flag files that have been generated by fragments on which this depends then use 887 // them to validate the flag file generated by the rules created by this method. 888 if len(allFlagsPaths) > 0 { 889 validFile := buildRuleValidateOverlappingCsvFiles(ctx, name, desc, outputPath, allFlagsPaths) 890 891 // Add the file that indicates that the file generated by this is valid. 892 // 893 // This will cause the validation rule above to be run any time that the output of this rule 894 // changes but the validation will run in parallel with other rules that depend on this file. 895 command.Validation(validFile) 896 } 897 898 rule.Build(name, desc) 899} 900 901// buildRuleValidateOverlappingCsvFiles checks that the modular CSV files, i.e. the files generated 902// by the individual bootclasspath_fragment modules are subsets of the monolithic CSV file. 903func buildRuleValidateOverlappingCsvFiles(ctx android.BuilderContext, name string, desc string, monolithicFilePath android.WritablePath, modularFilePaths android.Paths) android.WritablePath { 904 // The file which is used to record that the flags file is valid. 905 validFile := pathForValidation(ctx, monolithicFilePath) 906 907 // Create a rule to validate the output from the following rule. 908 rule := android.NewRuleBuilder(pctx, ctx) 909 rule.Command(). 910 BuiltTool("verify_overlaps"). 911 Input(monolithicFilePath). 912 Inputs(modularFilePaths). 913 // If validation passes then update the file that records that. 914 Text("&& touch").Output(validFile) 915 rule.Build(name+"Validation", desc+" validation") 916 917 return validFile 918} 919 920// hiddenAPIRulesForBootclasspathFragment will generate all the flags for a fragment of the 921// bootclasspath and then encode the flags into the boot dex files. 922// 923// It takes: 924// * Map from android.SdkKind to stub dex jar paths defining the API for that sdk kind. 925// * The list of modules that are the contents of the fragment. 926// * The additional manually curated flag files to use. 927// 928// It generates: 929// * stub-flags.csv 930// * annotation-flags.csv 931// * metadata.csv 932// * index.csv 933// * all-flags.csv 934// * encoded boot dex files 935func hiddenAPIRulesForBootclasspathFragment(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { 936 hiddenApiSubDir := "modular-hiddenapi" 937 938 // Gather information about the boot dex files for the boot libraries provided by this fragment. 939 bootDexInfoByModule := extractBootDexInfoFromModules(ctx, contents) 940 941 // Generate the stub-flags.csv. 942 stubFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "stub-flags.csv") 943 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "modularHiddenAPIStubFlagsFile", "modular hiddenapi stub flags", stubFlagsCSV, bootDexInfoByModule.bootDexJars(), input, nil) 944 945 // Extract the classes jars from the contents. 946 classesJars := extractClassesJarsFromModules(contents) 947 948 // Generate the set of flags from the annotations in the source code. 949 annotationFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "annotation-flags.csv") 950 buildRuleToGenerateAnnotationFlags(ctx, "modular hiddenapi annotation flags", classesJars, stubFlagsCSV, annotationFlagsCSV) 951 952 // Generate the metadata from the annotations in the source code. 953 metadataCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "metadata.csv") 954 buildRuleToGenerateMetadata(ctx, "modular hiddenapi metadata", classesJars, stubFlagsCSV, metadataCSV) 955 956 // Generate the index file from the CSV files in the classes jars. 957 indexCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "index.csv") 958 buildRuleToGenerateIndex(ctx, "modular hiddenapi index", classesJars, indexCSV) 959 960 // Removed APIs need to be marked and in order to do that the hiddenAPIInfo needs to specify files 961 // containing dex signatures of all the removed APIs. In the monolithic files that is done by 962 // manually combining all the removed.txt files for each API and then converting them to dex 963 // signatures, see the combined-removed-dex module. This does that automatically by using the 964 // *removed.txt files retrieved from the java_sdk_library modules that are specified in the 965 // stub_libs and contents properties of a bootclasspath_fragment. 966 removedDexSignatures := buildRuleToGenerateRemovedDexSignatures(ctx, input.RemovedTxtFiles) 967 968 // Generate the all-flags.csv which are the flags that will, in future, be encoded into the dex 969 // files. 970 allFlagsCSV := android.PathForModuleOut(ctx, hiddenApiSubDir, "all-flags.csv") 971 buildRuleToGenerateHiddenApiFlags(ctx, "modularHiddenApiAllFlags", "modular hiddenapi all flags", allFlagsCSV, stubFlagsCSV, android.Paths{annotationFlagsCSV}, input.FlagFilesByCategory, nil, removedDexSignatures) 972 973 // Encode the flags into the boot dex files. 974 encodedBootDexJarsByModule := map[string]android.Path{} 975 outputDir := android.PathForModuleOut(ctx, "hiddenapi-modular/encoded").OutputPath 976 for _, name := range android.SortedStringKeys(bootDexInfoByModule) { 977 bootDexInfo := bootDexInfoByModule[name] 978 unencodedDex := bootDexInfo.path 979 encodedDex := hiddenAPIEncodeDex(ctx, unencodedDex, allFlagsCSV, bootDexInfo.uncompressDex, outputDir) 980 encodedBootDexJarsByModule[name] = encodedDex 981 } 982 983 // Store the paths in the info for use by other modules and sdk snapshot generation. 984 output := HiddenAPIOutput{ 985 HiddenAPIFlagOutput: HiddenAPIFlagOutput{ 986 StubFlagsPath: stubFlagsCSV, 987 AnnotationFlagsPath: annotationFlagsCSV, 988 MetadataPath: metadataCSV, 989 IndexPath: indexCSV, 990 AllFlagsPath: allFlagsCSV, 991 }, 992 EncodedBootDexFilesByModule: encodedBootDexJarsByModule, 993 } 994 return &output 995} 996 997func buildRuleToGenerateRemovedDexSignatures(ctx android.ModuleContext, removedTxtFiles android.Paths) android.OptionalPath { 998 if len(removedTxtFiles) == 0 { 999 return android.OptionalPath{} 1000 } 1001 1002 output := android.PathForModuleOut(ctx, "modular-hiddenapi/removed-dex-signatures.txt") 1003 1004 rule := android.NewRuleBuilder(pctx, ctx) 1005 rule.Command(). 1006 BuiltTool("metalava"). 1007 Flag("--no-banner"). 1008 Inputs(removedTxtFiles). 1009 FlagWithOutput("--dex-api ", output) 1010 rule.Build("modular-hiddenapi-removed-dex-signatures", "modular hiddenapi removed dex signatures") 1011 return android.OptionalPathForPath(output) 1012} 1013 1014// extractBootDexJarsFromModules extracts the boot dex jars from the supplied modules. 1015func extractBootDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { 1016 bootDexJars := bootDexJarByModule{} 1017 for _, module := range contents { 1018 hiddenAPIModule := hiddenAPIModuleFromModule(ctx, module) 1019 if hiddenAPIModule == nil { 1020 continue 1021 } 1022 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) 1023 bootDexJars.addPath(module, bootDexJar) 1024 } 1025 return bootDexJars 1026} 1027 1028func hiddenAPIModuleFromModule(ctx android.BaseModuleContext, module android.Module) hiddenAPIModule { 1029 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { 1030 return hiddenAPIModule 1031 } else if _, ok := module.(*DexImport); ok { 1032 // Ignore this for the purposes of hidden API processing 1033 } else { 1034 ctx.ModuleErrorf("module %s does not implement hiddenAPIModule", module) 1035 } 1036 1037 return nil 1038} 1039 1040// bootDexInfo encapsulates both the path and uncompressDex status retrieved from a hiddenAPIModule. 1041type bootDexInfo struct { 1042 // The path to the dex jar that has not had hidden API flags encoded into it. 1043 path android.Path 1044 1045 // Indicates whether the dex jar needs uncompressing before encoding. 1046 uncompressDex bool 1047} 1048 1049// bootDexInfoByModule is a map from module name (as returned by module.Name()) to the boot dex 1050// path (as returned by hiddenAPIModule.bootDexJar()) and the uncompressDex flag. 1051type bootDexInfoByModule map[string]bootDexInfo 1052 1053// bootDexJars returns the boot dex jar paths sorted by their keys. 1054func (b bootDexInfoByModule) bootDexJars() android.Paths { 1055 paths := android.Paths{} 1056 for _, m := range android.SortedStringKeys(b) { 1057 paths = append(paths, b[m].path) 1058 } 1059 return paths 1060} 1061 1062// extractBootDexInfoFromModules extracts the boot dex jar and uncompress dex state from 1063// each of the supplied modules which must implement hiddenAPIModule. 1064func extractBootDexInfoFromModules(ctx android.ModuleContext, contents []android.Module) bootDexInfoByModule { 1065 bootDexJarsByModule := bootDexInfoByModule{} 1066 for _, module := range contents { 1067 hiddenAPIModule := module.(hiddenAPIModule) 1068 bootDexJar := retrieveBootDexJarFromHiddenAPIModule(ctx, hiddenAPIModule) 1069 bootDexJarsByModule[module.Name()] = bootDexInfo{ 1070 path: bootDexJar, 1071 uncompressDex: *hiddenAPIModule.uncompressDex(), 1072 } 1073 } 1074 1075 return bootDexJarsByModule 1076} 1077 1078// retrieveBootDexJarFromHiddenAPIModule retrieves the boot dex jar from the hiddenAPIModule. 1079// 1080// If the module does not provide a boot dex jar, i.e. the returned boot dex jar is nil, then that 1081// create a fake path and either report an error immediately or defer reporting of the error until 1082// the path is actually used. 1083func retrieveBootDexJarFromHiddenAPIModule(ctx android.ModuleContext, module hiddenAPIModule) android.Path { 1084 bootDexJar := module.bootDexJar() 1085 if bootDexJar == nil { 1086 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/boot-dex/%s.jar", module.Name())) 1087 bootDexJar = fake 1088 1089 handleMissingDexBootFile(ctx, module, fake) 1090 } 1091 return bootDexJar 1092} 1093 1094// extractClassesJarsFromModules extracts the class jars from the supplied modules. 1095func extractClassesJarsFromModules(contents []android.Module) android.Paths { 1096 classesJars := android.Paths{} 1097 for _, module := range contents { 1098 classesJars = append(classesJars, retrieveClassesJarsFromModule(module)...) 1099 } 1100 return classesJars 1101} 1102 1103// retrieveClassesJarsFromModule retrieves the classes jars from the supplied module. 1104func retrieveClassesJarsFromModule(module android.Module) android.Paths { 1105 if hiddenAPIModule, ok := module.(hiddenAPIModule); ok { 1106 return hiddenAPIModule.classesJars() 1107 } 1108 1109 return nil 1110} 1111 1112// deferReportingMissingBootDexJar returns true if a missing boot dex jar should not be reported by 1113// Soong but should instead only be reported in ninja if the file is actually built. 1114func deferReportingMissingBootDexJar(ctx android.ModuleContext, module android.Module) bool { 1115 // TODO(b/179354495): Remove this workaround when it is unnecessary. 1116 // Prebuilt modules like framework-wifi do not yet provide dex implementation jars. So, 1117 // create a fake one that will cause a build error only if it is used. 1118 if ctx.Config().AlwaysUsePrebuiltSdks() { 1119 return true 1120 } 1121 1122 // Any missing dependency should be allowed. 1123 if ctx.Config().AllowMissingDependencies() { 1124 return true 1125 } 1126 1127 // A bootclasspath module that is part of a versioned sdk never provides a boot dex jar as there 1128 // is no equivalently versioned prebuilt APEX file from which it can be obtained. However, 1129 // versioned bootclasspath modules are processed by Soong so in order to avoid them causing build 1130 // failures missing boot dex jars need to be deferred. 1131 if android.IsModuleInVersionedSdk(ctx.Module()) { 1132 return true 1133 } 1134 1135 // This is called for both platform_bootclasspath and bootclasspath_fragment modules. 1136 // 1137 // A bootclasspath_fragment module should only use the APEX variant of source or prebuilt modules. 1138 // Ideally, a bootclasspath_fragment module should never have a platform variant created for it 1139 // but unfortunately, due to b/187910671 it does. 1140 // 1141 // That causes issues when obtaining a boot dex jar for a prebuilt module as a prebuilt module 1142 // used by a bootclasspath_fragment can only provide a boot dex jar when it is part of APEX, i.e. 1143 // has an APEX variant not a platform variant. 1144 // 1145 // There are some other situations when a prebuilt module used by a bootclasspath_fragment cannot 1146 // provide a boot dex jar: 1147 // 1. If the bootclasspath_fragment is not exported by the prebuilt_apex/apex_set module then it 1148 // does not have an APEX variant and only has a platform variant and neither do its content 1149 // modules. 1150 // 2. Some build configurations, e.g. setting TARGET_BUILD_USE_PREBUILT_SDKS causes all 1151 // java_sdk_library_import modules to be treated as preferred and as many of them are not part 1152 // of an apex they cannot provide a boot dex jar. 1153 // 1154 // The first case causes problems when the affected prebuilt modules are preferred but that is an 1155 // invalid configuration and it is ok for it to fail as the work to enable that is not yet 1156 // complete. The second case is used for building targets that do not use boot dex jars and so 1157 // deferring error reporting to ninja is fine as the affected ninja targets should never be built. 1158 // That is handled above. 1159 // 1160 // A platform_bootclasspath module can use libraries from both platform and APEX variants. Unlike 1161 // the bootclasspath_fragment it supports dex_import modules which provides the dex file. So, it 1162 // can obtain a boot dex jar from a prebuilt that is not part of an APEX. However, it is assumed 1163 // that if the library can be part of an APEX then it is the APEX variant that is used. 1164 // 1165 // This check handles the slightly different requirements of the bootclasspath_fragment and 1166 // platform_bootclasspath modules by only deferring error reporting for the platform variant of 1167 // a prebuilt modules that has other variants which are part of an APEX. 1168 // 1169 // TODO(b/187910671): Remove this once platform variants are no longer created unnecessarily. 1170 if android.IsModulePrebuilt(module) { 1171 // An inactive source module can still contribute to the APEX but an inactive prebuilt module 1172 // should not contribute to anything. So, rather than have a missing dex jar cause a Soong 1173 // failure defer the error reporting to Ninja. Unless the prebuilt build target is explicitly 1174 // built Ninja should never use the dex jar file. 1175 if !isActiveModule(module) { 1176 return true 1177 } 1178 1179 if am, ok := module.(android.ApexModule); ok && am.InAnyApex() { 1180 apexInfo := ctx.OtherModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo) 1181 if apexInfo.IsForPlatform() { 1182 return true 1183 } 1184 } 1185 } 1186 1187 return false 1188} 1189 1190// handleMissingDexBootFile will either log a warning or create an error rule to create the fake 1191// file depending on the value returned from deferReportingMissingBootDexJar. 1192func handleMissingDexBootFile(ctx android.ModuleContext, module android.Module, fake android.WritablePath) { 1193 if deferReportingMissingBootDexJar(ctx, module) { 1194 // Create an error rule that pretends to create the output file but will actually fail if it 1195 // is run. 1196 ctx.Build(pctx, android.BuildParams{ 1197 Rule: android.ErrorRule, 1198 Output: fake, 1199 Args: map[string]string{ 1200 "error": fmt.Sprintf("missing dependencies: boot dex jar for %s", module), 1201 }, 1202 }) 1203 } else { 1204 ctx.ModuleErrorf("module %s does not provide a dex jar", module) 1205 } 1206} 1207 1208// retrieveEncodedBootDexJarFromModule returns a path to the boot dex jar from the supplied module's 1209// DexJarBuildPath() method. 1210// 1211// The returned path will usually be to a dex jar file that has been encoded with hidden API flags. 1212// However, under certain conditions, e.g. errors, or special build configurations it will return 1213// a path to a fake file. 1214func retrieveEncodedBootDexJarFromModule(ctx android.ModuleContext, module android.Module) android.Path { 1215 bootDexJar := module.(interface{ DexJarBuildPath() android.Path }).DexJarBuildPath() 1216 if bootDexJar == nil { 1217 fake := android.PathForModuleOut(ctx, fmt.Sprintf("fake/encoded-dex/%s.jar", module.Name())) 1218 bootDexJar = fake 1219 1220 handleMissingDexBootFile(ctx, module, fake) 1221 } 1222 return bootDexJar 1223} 1224 1225// extractEncodedDexJarsFromModules extracts the encoded dex jars from the supplied modules. 1226func extractEncodedDexJarsFromModules(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { 1227 encodedDexJarsByModuleName := bootDexJarByModule{} 1228 for _, module := range contents { 1229 path := retrieveEncodedBootDexJarFromModule(ctx, module) 1230 encodedDexJarsByModuleName.addPath(module, path) 1231 } 1232 return encodedDexJarsByModuleName 1233} 1234