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