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