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 "path/filepath" 20 "reflect" 21 "strings" 22 23 "android/soong/android" 24 "android/soong/dexpreopt" 25 26 "github.com/google/blueprint/proptools" 27 28 "github.com/google/blueprint" 29) 30 31func init() { 32 registerBootclasspathFragmentBuildComponents(android.InitRegistrationContext) 33 34 android.RegisterSdkMemberType(&bootclasspathFragmentMemberType{ 35 SdkMemberTypeBase: android.SdkMemberTypeBase{ 36 PropertyName: "bootclasspath_fragments", 37 SupportsSdk: true, 38 }, 39 }) 40} 41 42func registerBootclasspathFragmentBuildComponents(ctx android.RegistrationContext) { 43 ctx.RegisterModuleType("bootclasspath_fragment", bootclasspathFragmentFactory) 44 ctx.RegisterModuleType("prebuilt_bootclasspath_fragment", prebuiltBootclasspathFragmentFactory) 45} 46 47type bootclasspathFragmentContentDependencyTag struct { 48 blueprint.BaseDependencyTag 49} 50 51// Avoid having to make bootclasspath_fragment content visible to the bootclasspath_fragment. 52// 53// This is a temporary workaround to make it easier to migrate to bootclasspath_fragment modules 54// with proper dependencies. 55// TODO(b/177892522): Remove this and add needed visibility. 56func (b bootclasspathFragmentContentDependencyTag) ExcludeFromVisibilityEnforcement() { 57} 58 59// The bootclasspath_fragment contents must never depend on prebuilts. 60func (b bootclasspathFragmentContentDependencyTag) ReplaceSourceWithPrebuilt() bool { 61 return false 62} 63 64// SdkMemberType causes dependencies added with this tag to be automatically added to the sdk as if 65// they were specified using java_boot_libs or java_sdk_libs. 66func (b bootclasspathFragmentContentDependencyTag) SdkMemberType(child android.Module) android.SdkMemberType { 67 // If the module is a java_sdk_library then treat it as if it was specified in the java_sdk_libs 68 // property, otherwise treat if it was specified in the java_boot_libs property. 69 if javaSdkLibrarySdkMemberType.IsInstance(child) { 70 return javaSdkLibrarySdkMemberType 71 } 72 73 return javaBootLibsSdkMemberType 74} 75 76func (b bootclasspathFragmentContentDependencyTag) ExportMember() bool { 77 return true 78} 79 80// Contents of bootclasspath fragments in an apex are considered to be directly in the apex, as if 81// they were listed in java_libs. 82func (b bootclasspathFragmentContentDependencyTag) CopyDirectlyInAnyApex() {} 83 84// Contents of bootclasspath fragments require files from prebuilt apex files. 85func (b bootclasspathFragmentContentDependencyTag) RequiresFilesFromPrebuiltApex() {} 86 87// The tag used for the dependency between the bootclasspath_fragment module and its contents. 88var bootclasspathFragmentContentDepTag = bootclasspathFragmentContentDependencyTag{} 89 90var _ android.ExcludeFromVisibilityEnforcementTag = bootclasspathFragmentContentDepTag 91var _ android.ReplaceSourceWithPrebuilt = bootclasspathFragmentContentDepTag 92var _ android.SdkMemberTypeDependencyTag = bootclasspathFragmentContentDepTag 93var _ android.CopyDirectlyInAnyApexTag = bootclasspathFragmentContentDepTag 94var _ android.RequiresFilesFromPrebuiltApexTag = bootclasspathFragmentContentDepTag 95 96func IsBootclasspathFragmentContentDepTag(tag blueprint.DependencyTag) bool { 97 return tag == bootclasspathFragmentContentDepTag 98} 99 100// Properties that can be different when coverage is enabled. 101type BootclasspathFragmentCoverageAffectedProperties struct { 102 // The contents of this bootclasspath_fragment, could be either java_library, or java_sdk_library. 103 // 104 // A java_sdk_library specified here will also be treated as if it was specified on the stub_libs 105 // property. 106 // 107 // The order of this list matters as it is the order that is used in the bootclasspath. 108 Contents []string 109 110 // The properties for specifying the API stubs provided by this fragment. 111 BootclasspathAPIProperties 112} 113 114type bootclasspathFragmentProperties struct { 115 // The name of the image this represents. 116 // 117 // If specified then it must be one of "art" or "boot". 118 Image_name *string 119 120 // Properties whose values need to differ with and without coverage. 121 BootclasspathFragmentCoverageAffectedProperties 122 Coverage BootclasspathFragmentCoverageAffectedProperties 123 124 // Hidden API related properties. 125 Hidden_api HiddenAPIFlagFileProperties 126 127 // The list of additional stub libraries which this fragment's contents use but which are not 128 // provided by another bootclasspath_fragment. 129 // 130 // Note, "android-non-updatable" is treated specially. While no such module exists it is treated 131 // as if it was a java_sdk_library. So, when public API stubs are needed then it will be replaced 132 // with "android-non-updatable.stubs", with "androidn-non-updatable.system.stubs" when the system 133 // stubs are needed and so on. 134 Additional_stubs []string 135 136 // Properties that allow a fragment to depend on other fragments. This is needed for hidden API 137 // processing as it needs access to all the classes used by a fragment including those provided 138 // by other fragments. 139 BootclasspathFragmentsDepsProperties 140} 141 142type BootclasspathFragmentModule struct { 143 android.ModuleBase 144 android.ApexModuleBase 145 android.SdkBase 146 ClasspathFragmentBase 147 148 properties bootclasspathFragmentProperties 149} 150 151// commonBootclasspathFragment defines the methods that are implemented by both source and prebuilt 152// bootclasspath fragment modules. 153type commonBootclasspathFragment interface { 154 // produceHiddenAPIOutput produces the all-flags.csv and intermediate files and encodes the flags 155 // into dex files. 156 // 157 // Returns a *HiddenAPIOutput containing the paths for the generated files. Returns nil if the 158 // module cannot contribute to hidden API processing, e.g. because it is a prebuilt module in a 159 // versioned sdk. 160 produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput 161 162 // produceBootImageFiles will attempt to produce rules to create the boot image files at the paths 163 // predefined in the bootImageConfig. 164 // 165 // If it could not create the files then it will return nil. Otherwise, it will return a map from 166 // android.ArchType to the predefined paths of the boot image files. 167 produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch 168} 169 170var _ commonBootclasspathFragment = (*BootclasspathFragmentModule)(nil) 171 172// bootImageFilesByArch is a map from android.ArchType to the paths to the boot image files. 173// 174// The paths include the .art, .oat and .vdex files, one for each of the modules from which the boot 175// image is created. 176type bootImageFilesByArch map[android.ArchType]android.Paths 177 178func bootclasspathFragmentFactory() android.Module { 179 m := &BootclasspathFragmentModule{} 180 m.AddProperties(&m.properties) 181 android.InitApexModule(m) 182 android.InitSdkAwareModule(m) 183 initClasspathFragment(m, BOOTCLASSPATH) 184 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) 185 186 android.AddLoadHook(m, func(ctx android.LoadHookContext) { 187 // If code coverage has been enabled for the framework then append the properties with 188 // coverage specific properties. 189 if ctx.Config().IsEnvTrue("EMMA_INSTRUMENT_FRAMEWORK") { 190 err := proptools.AppendProperties(&m.properties.BootclasspathFragmentCoverageAffectedProperties, &m.properties.Coverage, nil) 191 if err != nil { 192 ctx.PropertyErrorf("coverage", "error trying to append coverage specific properties: %s", err) 193 return 194 } 195 } 196 197 // Initialize the contents property from the image_name. 198 bootclasspathFragmentInitContentsFromImage(ctx, m) 199 }) 200 return m 201} 202 203// bootclasspathFragmentInitContentsFromImage will initialize the contents property from the image_name if 204// necessary. 205func bootclasspathFragmentInitContentsFromImage(ctx android.EarlyModuleContext, m *BootclasspathFragmentModule) { 206 contents := m.properties.Contents 207 if len(contents) == 0 { 208 ctx.PropertyErrorf("contents", "required property is missing") 209 return 210 } 211 212 if m.properties.Image_name == nil { 213 // Nothing to do. 214 return 215 } 216 217 imageName := proptools.String(m.properties.Image_name) 218 if imageName != "art" { 219 ctx.PropertyErrorf("image_name", `unknown image name %q, expected "art"`, imageName) 220 return 221 } 222 223 // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property. 224 if android.IsModuleInVersionedSdk(m) { 225 // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons: 226 // 1. There is no way to use this at the moment so ignoring it is safe. 227 // 2. Attempting to initialize the contents property from the configuration will end up having 228 // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems 229 // as the unversioned prebuilt could end up with an APEX variant created for the source 230 // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in 231 // turn will prevent it from accessing the dex implementation jar from that which will 232 // break hidden API processing, amongst others. 233 return 234 } 235 236 // Get the configuration for the art apex jars. Do not use getImageConfig(ctx) here as this is 237 // too early in the Soong processing for that to work. 238 global := dexpreopt.GetGlobalConfig(ctx) 239 modules := global.ArtApexJars 240 241 // Make sure that the apex specified in the configuration is consistent and is one for which 242 // this boot image is available. 243 commonApex := "" 244 for i := 0; i < modules.Len(); i++ { 245 apex := modules.Apex(i) 246 jar := modules.Jar(i) 247 if apex == "platform" { 248 ctx.ModuleErrorf("ArtApexJars is invalid as it requests a platform variant of %q", jar) 249 continue 250 } 251 if !m.AvailableFor(apex) { 252 ctx.ModuleErrorf("ArtApexJars configuration incompatible with this module, ArtApexJars expects this to be in apex %q but this is only in apexes %q", 253 apex, m.ApexAvailable()) 254 continue 255 } 256 if commonApex == "" { 257 commonApex = apex 258 } else if commonApex != apex { 259 ctx.ModuleErrorf("ArtApexJars configuration is inconsistent, expected all jars to be in the same apex but it specifies apex %q and %q", 260 commonApex, apex) 261 } 262 } 263} 264 265// bootclasspathImageNameContentsConsistencyCheck checks that the configuration that applies to this 266// module (if any) matches the contents. 267// 268// This should be a noop as if image_name="art" then the contents will be set from the ArtApexJars 269// config by bootclasspathFragmentInitContentsFromImage so it will be guaranteed to match. However, 270// in future this will not be the case. 271func (b *BootclasspathFragmentModule) bootclasspathImageNameContentsConsistencyCheck(ctx android.BaseModuleContext) { 272 imageName := proptools.String(b.properties.Image_name) 273 if imageName == "art" { 274 // TODO(b/177892522): Prebuilts (versioned or not) should not use the image_name property. 275 if android.IsModuleInVersionedSdk(b) { 276 // The module is a versioned prebuilt so ignore it. This is done for a couple of reasons: 277 // 1. There is no way to use this at the moment so ignoring it is safe. 278 // 2. Attempting to initialize the contents property from the configuration will end up having 279 // the versioned prebuilt depending on the unversioned prebuilt. That will cause problems 280 // as the unversioned prebuilt could end up with an APEX variant created for the source 281 // APEX which will prevent it from having an APEX variant for the prebuilt APEX which in 282 // turn will prevent it from accessing the dex implementation jar from that which will 283 // break hidden API processing, amongst others. 284 return 285 } 286 287 // Get the configuration for the art apex jars. 288 modules := b.getImageConfig(ctx).modules 289 configuredJars := modules.CopyOfJars() 290 291 // Skip the check if the configured jars list is empty as that is a common configuration when 292 // building targets that do not result in a system image. 293 if len(configuredJars) == 0 { 294 return 295 } 296 297 contents := b.properties.Contents 298 if !reflect.DeepEqual(configuredJars, contents) { 299 ctx.ModuleErrorf("inconsistency in specification of contents. ArtApexJars configuration specifies %#v, contents property specifies %#v", 300 configuredJars, contents) 301 } 302 } 303} 304 305var BootclasspathFragmentApexContentInfoProvider = blueprint.NewProvider(BootclasspathFragmentApexContentInfo{}) 306 307// BootclasspathFragmentApexContentInfo contains the bootclasspath_fragments contributions to the 308// apex contents. 309type BootclasspathFragmentApexContentInfo struct { 310 // The configured modules, will be empty if this is from a bootclasspath_fragment that does not 311 // set image_name: "art". 312 modules android.ConfiguredJarList 313 314 // Map from arch type to the boot image files. 315 bootImageFilesByArch bootImageFilesByArch 316 317 // Map from the base module name (without prebuilt_ prefix) of a fragment's contents module to the 318 // hidden API encoded dex jar path. 319 contentModuleDexJarPaths bootDexJarByModule 320} 321 322func (i BootclasspathFragmentApexContentInfo) Modules() android.ConfiguredJarList { 323 return i.modules 324} 325 326// Get a map from ArchType to the associated boot image's contents for Android. 327// 328// Extension boot images only return their own files, not the files of the boot images they extend. 329func (i BootclasspathFragmentApexContentInfo) AndroidBootImageFilesByArchType() bootImageFilesByArch { 330 return i.bootImageFilesByArch 331} 332 333// DexBootJarPathForContentModule returns the path to the dex boot jar for specified module. 334// 335// The dex boot jar is one which has had hidden API encoding performed on it. 336func (i BootclasspathFragmentApexContentInfo) DexBootJarPathForContentModule(module android.Module) (android.Path, error) { 337 // A bootclasspath_fragment cannot use a prebuilt library so Name() will return the base name 338 // without a prebuilt_ prefix so is safe to use as the key for the contentModuleDexJarPaths. 339 name := module.Name() 340 if dexJar, ok := i.contentModuleDexJarPaths[name]; ok { 341 return dexJar, nil 342 } else { 343 return nil, fmt.Errorf("unknown bootclasspath_fragment content module %s, expected one of %s", 344 name, strings.Join(android.SortedStringKeys(i.contentModuleDexJarPaths), ", ")) 345 } 346} 347 348func (b *BootclasspathFragmentModule) DepIsInSameApex(ctx android.BaseModuleContext, dep android.Module) bool { 349 tag := ctx.OtherModuleDependencyTag(dep) 350 if IsBootclasspathFragmentContentDepTag(tag) { 351 // Boot image contents are automatically added to apex. 352 return true 353 } 354 if android.IsMetaDependencyTag(tag) { 355 // Cross-cutting metadata dependencies are metadata. 356 return false 357 } 358 panic(fmt.Errorf("boot_image module %q should not have a dependency on %q via tag %s", b, dep, android.PrettyPrintTag(tag))) 359} 360 361func (b *BootclasspathFragmentModule) ShouldSupportSdkVersion(ctx android.BaseModuleContext, sdkVersion android.ApiLevel) error { 362 return nil 363} 364 365// ComponentDepsMutator adds dependencies onto modules before any prebuilt modules without a 366// corresponding source module are renamed. This means that adding a dependency using a name without 367// a prebuilt_ prefix will always resolve to a source module and when using a name with that prefix 368// it will always resolve to a prebuilt module. 369func (b *BootclasspathFragmentModule) ComponentDepsMutator(ctx android.BottomUpMutatorContext) { 370 module := ctx.Module() 371 _, isSourceModule := module.(*BootclasspathFragmentModule) 372 373 for _, name := range b.properties.Contents { 374 // A bootclasspath_fragment must depend only on other source modules, while the 375 // prebuilt_bootclasspath_fragment must only depend on other prebuilt modules. 376 // 377 // TODO(b/177892522) - avoid special handling of jacocoagent. 378 if !isSourceModule && name != "jacocoagent" { 379 name = android.PrebuiltNameFromSource(name) 380 } 381 ctx.AddDependency(module, bootclasspathFragmentContentDepTag, name) 382 } 383 384} 385 386func (b *BootclasspathFragmentModule) DepsMutator(ctx android.BottomUpMutatorContext) { 387 // Add dependencies onto all the modules that provide the API stubs for classes on this 388 // bootclasspath fragment. 389 hiddenAPIAddStubLibDependencies(ctx, b.properties.apiScopeToStubLibs()) 390 391 for _, additionalStubModule := range b.properties.Additional_stubs { 392 for _, apiScope := range hiddenAPISdkLibrarySupportedScopes { 393 // Add a dependency onto a possibly scope specific stub library. 394 scopeSpecificDependency := apiScope.scopeSpecificStubModule(ctx, additionalStubModule) 395 tag := hiddenAPIStubsDependencyTag{apiScope: apiScope, fromAdditionalDependency: true} 396 ctx.AddVariationDependencies(nil, tag, scopeSpecificDependency) 397 } 398 } 399 400 if SkipDexpreoptBootJars(ctx) { 401 return 402 } 403 404 // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The 405 // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). 406 dexpreopt.RegisterToolDeps(ctx) 407} 408 409func (b *BootclasspathFragmentModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { 410 // Add dependencies on all the fragments. 411 b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) 412} 413 414func (b *BootclasspathFragmentModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 415 // Only perform a consistency check if this module is the active module. That will prevent an 416 // unused prebuilt that was created without instrumentation from breaking an instrumentation 417 // build. 418 if isActiveModule(ctx.Module()) { 419 b.bootclasspathImageNameContentsConsistencyCheck(ctx) 420 } 421 422 // Generate classpaths.proto config 423 b.generateClasspathProtoBuildActions(ctx) 424 425 // Gather the bootclasspath fragment's contents. 426 var contents []android.Module 427 ctx.VisitDirectDeps(func(module android.Module) { 428 tag := ctx.OtherModuleDependencyTag(module) 429 if IsBootclasspathFragmentContentDepTag(tag) { 430 contents = append(contents, module) 431 } 432 }) 433 434 fragments := gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) 435 436 // Verify that the image_name specified on a bootclasspath_fragment is valid even if this is a 437 // prebuilt which will not use the image config. 438 imageConfig := b.getImageConfig(ctx) 439 440 // A versioned prebuilt_bootclasspath_fragment cannot and does not need to perform hidden API 441 // processing. It cannot do it because it is not part of a prebuilt_apex and so has no access to 442 // the correct dex implementation jar. It does not need to because the platform-bootclasspath 443 // always references the latest bootclasspath_fragments. 444 if !android.IsModuleInVersionedSdk(ctx.Module()) { 445 // Perform hidden API processing. 446 hiddenAPIOutput := b.generateHiddenAPIBuildActions(ctx, contents, fragments) 447 448 var bootImageFilesByArch bootImageFilesByArch 449 if imageConfig != nil { 450 // Delegate the production of the boot image files to a module type specific method. 451 common := ctx.Module().(commonBootclasspathFragment) 452 bootImageFilesByArch = common.produceBootImageFiles(ctx, imageConfig) 453 454 if shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { 455 // Zip the boot image files up, if available. This will generate the zip file in a 456 // predefined location. 457 buildBootImageZipInPredefinedLocation(ctx, imageConfig, bootImageFilesByArch) 458 459 // Copy the dex jars of this fragment's content modules to their predefined locations. 460 copyBootJarsToPredefinedLocations(ctx, hiddenAPIOutput.EncodedBootDexFilesByModule, imageConfig.dexPathsByModule) 461 } 462 } 463 464 // A prebuilt fragment cannot contribute to an apex. 465 if !android.IsModulePrebuilt(ctx.Module()) { 466 // Provide the apex content info. 467 b.provideApexContentInfo(ctx, imageConfig, hiddenAPIOutput, bootImageFilesByArch) 468 } 469 } 470} 471 472// shouldCopyBootFilesToPredefinedLocations determines whether the current module should copy boot 473// files, e.g. boot dex jars or boot image files, to the predefined location expected by the rest 474// of the build. 475// 476// This ensures that only a single module will copy its files to the image configuration. 477func shouldCopyBootFilesToPredefinedLocations(ctx android.ModuleContext, imageConfig *bootImageConfig) bool { 478 // Bootclasspath fragment modules that are for the platform do not produce boot related files. 479 apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) 480 if apexInfo.IsForPlatform() { 481 return false 482 } 483 484 // If the image configuration has no modules specified then it means that the build has been 485 // configured to build something other than a boot image, e.g. an sdk, so do not try and copy the 486 // files. 487 if imageConfig.modules.Len() == 0 { 488 return false 489 } 490 491 // Only copy files from the module that is preferred. 492 return isActiveModule(ctx.Module()) 493} 494 495// provideApexContentInfo creates, initializes and stores the apex content info for use by other 496// modules. 497func (b *BootclasspathFragmentModule) provideApexContentInfo(ctx android.ModuleContext, imageConfig *bootImageConfig, hiddenAPIOutput *HiddenAPIOutput, bootImageFilesByArch bootImageFilesByArch) { 498 // Construct the apex content info from the config. 499 info := BootclasspathFragmentApexContentInfo{ 500 // Populate the apex content info with paths to the dex jars. 501 contentModuleDexJarPaths: hiddenAPIOutput.EncodedBootDexFilesByModule, 502 } 503 504 if imageConfig != nil { 505 info.modules = imageConfig.modules 506 } 507 508 info.bootImageFilesByArch = bootImageFilesByArch 509 510 // Make the apex content info available for other modules. 511 ctx.SetProvider(BootclasspathFragmentApexContentInfoProvider, info) 512} 513 514// generateClasspathProtoBuildActions generates all required build actions for classpath.proto config 515func (b *BootclasspathFragmentModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) { 516 var classpathJars []classpathJar 517 if "art" == proptools.String(b.properties.Image_name) { 518 // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH 519 classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) 520 } else { 521 classpathJars = configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), b.classpathType) 522 } 523 b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars) 524} 525 526func (b *BootclasspathFragmentModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { 527 if "art" == proptools.String(b.properties.Image_name) { 528 return b.getImageConfig(ctx).modules 529 } 530 531 global := dexpreopt.GetGlobalConfig(ctx) 532 533 possibleUpdatableModules := gatherPossibleUpdatableModuleNamesAndStems(ctx, b.properties.Contents, bootclasspathFragmentContentDepTag) 534 535 // Only create configs for updatable boot jars. Non-updatable boot jars must be part of the 536 // platform_bootclasspath's classpath proto config to guarantee that they come before any 537 // updatable jars at runtime. 538 jars := global.UpdatableBootJars.Filter(possibleUpdatableModules) 539 540 // TODO(satayev): for apex_test we want to include all contents unconditionally to classpaths 541 // config. However, any test specific jars would not be present in UpdatableBootJars. Instead, 542 // we should check if we are creating a config for apex_test via ApexInfo and amend the values. 543 // This is an exception to support end-to-end test for SdkExtensions, until such support exists. 544 if android.InList("test_framework-sdkextensions", possibleUpdatableModules) { 545 jars = jars.Append("com.android.sdkext", "test_framework-sdkextensions") 546 } 547 return jars 548} 549 550func (b *BootclasspathFragmentModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { 551 // Get a map of the image configs that are supported. 552 imageConfigs := genBootImageConfigs(ctx) 553 554 // Retrieve the config for this image. 555 imageNamePtr := b.properties.Image_name 556 if imageNamePtr == nil { 557 return nil 558 } 559 560 imageName := *imageNamePtr 561 imageConfig := imageConfigs[imageName] 562 if imageConfig == nil { 563 ctx.PropertyErrorf("image_name", "Unknown image name %q, expected one of %s", imageName, strings.Join(android.SortedStringKeys(imageConfigs), ", ")) 564 return nil 565 } 566 return imageConfig 567} 568 569// generateHiddenAPIBuildActions generates all the hidden API related build rules. 570func (b *BootclasspathFragmentModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) *HiddenAPIOutput { 571 572 // Create hidden API input structure. 573 input := b.createHiddenAPIFlagInput(ctx, contents, fragments) 574 575 // Delegate the production of the hidden API all-flags.csv file to a module type specific method. 576 common := ctx.Module().(commonBootclasspathFragment) 577 output := common.produceHiddenAPIOutput(ctx, contents, input) 578 579 // Initialize a HiddenAPIInfo structure. 580 hiddenAPIInfo := HiddenAPIInfo{ 581 // The monolithic hidden API processing needs access to the flag files that override the default 582 // flags from all the fragments whether or not they actually perform their own hidden API flag 583 // generation. That is because the monolithic hidden API processing uses those flag files to 584 // perform its own flag generation. 585 FlagFilesByCategory: input.FlagFilesByCategory, 586 587 // Other bootclasspath_fragments that depend on this need the transitive set of stub dex jars 588 // from this to resolve any references from their code to classes provided by this fragment 589 // and the fragments this depends upon. 590 TransitiveStubDexJarsByScope: input.transitiveStubDexJarsByScope(), 591 } 592 593 // The monolithic hidden API processing also needs access to all the output files produced by 594 // hidden API processing of this fragment. 595 hiddenAPIInfo.HiddenAPIFlagOutput = (*output).HiddenAPIFlagOutput 596 597 // Provide it for use by other modules. 598 ctx.SetProvider(HiddenAPIInfoProvider, hiddenAPIInfo) 599 600 return output 601} 602 603// retrieveLegacyEncodedBootDexFiles attempts to retrieve the legacy encoded boot dex jar files. 604func retrieveLegacyEncodedBootDexFiles(ctx android.ModuleContext, contents []android.Module) bootDexJarByModule { 605 // If the current bootclasspath_fragment is the active module or a source module then retrieve the 606 // encoded dex files, otherwise return an empty map. 607 // 608 // An inactive (i.e. not preferred) bootclasspath_fragment needs to retrieve the encoded dex jars 609 // as they are still needed by an apex. An inactive prebuilt_bootclasspath_fragment does not need 610 // to do so and may not yet have access to dex boot jars from a prebuilt_apex/apex_set. 611 if isActiveModule(ctx.Module()) || !android.IsModulePrebuilt(ctx.Module()) { 612 return extractEncodedDexJarsFromModules(ctx, contents) 613 } else { 614 return nil 615 } 616} 617 618// createHiddenAPIFlagInput creates a HiddenAPIFlagInput struct and initializes it with information derived 619// from the properties on this module and its dependencies. 620func (b *BootclasspathFragmentModule) createHiddenAPIFlagInput(ctx android.ModuleContext, contents []android.Module, fragments []android.Module) HiddenAPIFlagInput { 621 // Merge the HiddenAPIInfo from all the fragment dependencies. 622 dependencyHiddenApiInfo := newHiddenAPIInfo() 623 dependencyHiddenApiInfo.mergeFromFragmentDeps(ctx, fragments) 624 625 // Create hidden API flag input structure. 626 input := newHiddenAPIFlagInput() 627 628 // Update the input structure with information obtained from the stub libraries. 629 input.gatherStubLibInfo(ctx, contents) 630 631 // Populate with flag file paths from the properties. 632 input.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api) 633 634 // Add the stub dex jars from this module's fragment dependencies. 635 input.DependencyStubDexJarsByScope.addStubDexJarsByModule(dependencyHiddenApiInfo.TransitiveStubDexJarsByScope) 636 637 return input 638} 639 640// produceHiddenAPIOutput produces the hidden API all-flags.csv file (and supporting files) 641// for the fragment as well as encoding the flags in the boot dex jars. 642func (b *BootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { 643 // Generate the rules to create the hidden API flags and update the supplied hiddenAPIInfo with the 644 // paths to the created files. 645 return hiddenAPIRulesForBootclasspathFragment(ctx, contents, input) 646} 647 648// produceBootImageFiles builds the boot image files from the source if it is required. 649func (b *BootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { 650 if SkipDexpreoptBootJars(ctx) { 651 return nil 652 } 653 654 // Only generate the boot image if the configuration does not skip it. 655 return b.generateBootImageBuildActions(ctx, imageConfig) 656} 657 658// generateBootImageBuildActions generates ninja rules to create the boot image if required for this 659// module. 660// 661// If it could not create the files then it will return nil. Otherwise, it will return a map from 662// android.ArchType to the predefined paths of the boot image files. 663func (b *BootclasspathFragmentModule) generateBootImageBuildActions(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { 664 global := dexpreopt.GetGlobalConfig(ctx) 665 if !shouldBuildBootImages(ctx.Config(), global) { 666 return nil 667 } 668 669 // Bootclasspath fragment modules that are for the platform do not produce a boot image. 670 apexInfo := ctx.Provider(android.ApexInfoProvider).(android.ApexInfo) 671 if apexInfo.IsForPlatform() { 672 return nil 673 } 674 675 // Bootclasspath fragment modules that are versioned do not produce a boot image. 676 if android.IsModuleInVersionedSdk(ctx.Module()) { 677 return nil 678 } 679 680 // Build a profile for the image config and then use that to build the boot image. 681 profile := bootImageProfileRule(ctx, imageConfig) 682 683 // Build boot image files for the host variants. 684 buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) 685 686 // Build boot image files for the android variants. 687 androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) 688 689 // Return the boot image files for the android variants for inclusion in an APEX and to be zipped 690 // up for the dist. 691 return androidBootImageFilesByArch 692} 693 694type bootclasspathFragmentMemberType struct { 695 android.SdkMemberTypeBase 696} 697 698func (b *bootclasspathFragmentMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) { 699 mctx.AddVariationDependencies(nil, dependencyTag, names...) 700} 701 702func (b *bootclasspathFragmentMemberType) IsInstance(module android.Module) bool { 703 _, ok := module.(*BootclasspathFragmentModule) 704 return ok 705} 706 707func (b *bootclasspathFragmentMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule { 708 if b.PropertyName == "boot_images" { 709 return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image") 710 } else { 711 return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_bootclasspath_fragment") 712 } 713} 714 715func (b *bootclasspathFragmentMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties { 716 return &bootclasspathFragmentSdkMemberProperties{} 717} 718 719type bootclasspathFragmentSdkMemberProperties struct { 720 android.SdkMemberPropertiesBase 721 722 // The image name 723 Image_name *string 724 725 // Contents of the bootclasspath fragment 726 Contents []string 727 728 // Stub_libs properties. 729 Stub_libs []string 730 Core_platform_stub_libs []string 731 732 // Flag files by *hiddenAPIFlagFileCategory 733 Flag_files_by_category FlagFilesByCategory 734 735 // The path to the generated stub-flags.csv file. 736 Stub_flags_path android.OptionalPath 737 738 // The path to the generated annotation-flags.csv file. 739 Annotation_flags_path android.OptionalPath 740 741 // The path to the generated metadata.csv file. 742 Metadata_path android.OptionalPath 743 744 // The path to the generated index.csv file. 745 Index_path android.OptionalPath 746 747 // The path to the generated all-flags.csv file. 748 All_flags_path android.OptionalPath 749} 750 751func (b *bootclasspathFragmentSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) { 752 module := variant.(*BootclasspathFragmentModule) 753 754 b.Image_name = module.properties.Image_name 755 b.Contents = module.properties.Contents 756 757 // Get the hidden API information from the module. 758 mctx := ctx.SdkModuleContext() 759 hiddenAPIInfo := mctx.OtherModuleProvider(module, HiddenAPIInfoProvider).(HiddenAPIInfo) 760 b.Flag_files_by_category = hiddenAPIInfo.FlagFilesByCategory 761 762 // Copy all the generated file paths. 763 b.Stub_flags_path = android.OptionalPathForPath(hiddenAPIInfo.StubFlagsPath) 764 b.Annotation_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AnnotationFlagsPath) 765 b.Metadata_path = android.OptionalPathForPath(hiddenAPIInfo.MetadataPath) 766 b.Index_path = android.OptionalPathForPath(hiddenAPIInfo.IndexPath) 767 b.All_flags_path = android.OptionalPathForPath(hiddenAPIInfo.AllFlagsPath) 768 769 // Copy stub_libs properties. 770 b.Stub_libs = module.properties.Api.Stub_libs 771 b.Core_platform_stub_libs = module.properties.Core_platform_api.Stub_libs 772} 773 774func (b *bootclasspathFragmentSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) { 775 if b.Image_name != nil { 776 propertySet.AddProperty("image_name", *b.Image_name) 777 } 778 779 builder := ctx.SnapshotBuilder() 780 requiredMemberDependency := builder.SdkMemberReferencePropertyTag(true) 781 782 if len(b.Contents) > 0 { 783 propertySet.AddPropertyWithTag("contents", b.Contents, requiredMemberDependency) 784 } 785 786 if len(b.Stub_libs) > 0 { 787 apiPropertySet := propertySet.AddPropertySet("api") 788 apiPropertySet.AddPropertyWithTag("stub_libs", b.Stub_libs, requiredMemberDependency) 789 } 790 if len(b.Core_platform_stub_libs) > 0 { 791 corePlatformApiPropertySet := propertySet.AddPropertySet("core_platform_api") 792 corePlatformApiPropertySet.AddPropertyWithTag("stub_libs", b.Core_platform_stub_libs, requiredMemberDependency) 793 } 794 795 hiddenAPISet := propertySet.AddPropertySet("hidden_api") 796 hiddenAPIDir := "hiddenapi" 797 798 // Copy manually curated flag files specified on the bootclasspath_fragment. 799 if b.Flag_files_by_category != nil { 800 for _, category := range HiddenAPIFlagFileCategories { 801 paths := b.Flag_files_by_category[category] 802 if len(paths) > 0 { 803 dests := []string{} 804 for _, p := range paths { 805 dest := filepath.Join(hiddenAPIDir, p.Base()) 806 builder.CopyToSnapshot(p, dest) 807 dests = append(dests, dest) 808 } 809 hiddenAPISet.AddProperty(category.PropertyName, dests) 810 } 811 } 812 } 813 814 copyOptionalPath := func(path android.OptionalPath, property string) { 815 if path.Valid() { 816 p := path.Path() 817 dest := filepath.Join(hiddenAPIDir, p.Base()) 818 builder.CopyToSnapshot(p, dest) 819 hiddenAPISet.AddProperty(property, dest) 820 } 821 } 822 823 // Copy all the generated files, if available. 824 copyOptionalPath(b.Stub_flags_path, "stub_flags") 825 copyOptionalPath(b.Annotation_flags_path, "annotation_flags") 826 copyOptionalPath(b.Metadata_path, "metadata") 827 copyOptionalPath(b.Index_path, "index") 828 copyOptionalPath(b.All_flags_path, "all_flags") 829} 830 831var _ android.SdkMemberType = (*bootclasspathFragmentMemberType)(nil) 832 833// prebuiltBootclasspathFragmentProperties contains additional prebuilt_bootclasspath_fragment 834// specific properties. 835type prebuiltBootclasspathFragmentProperties struct { 836 Hidden_api struct { 837 // The path to the stub-flags.csv file created by the bootclasspath_fragment. 838 Stub_flags *string `android:"path"` 839 840 // The path to the annotation-flags.csv file created by the bootclasspath_fragment. 841 Annotation_flags *string `android:"path"` 842 843 // The path to the metadata.csv file created by the bootclasspath_fragment. 844 Metadata *string `android:"path"` 845 846 // The path to the index.csv file created by the bootclasspath_fragment. 847 Index *string `android:"path"` 848 849 // The path to the all-flags.csv file created by the bootclasspath_fragment. 850 All_flags *string `android:"path"` 851 } 852} 853 854// A prebuilt version of the bootclasspath_fragment module. 855// 856// At the moment this is basically just a bootclasspath_fragment module that can be used as a 857// prebuilt. Eventually as more functionality is migrated into the bootclasspath_fragment module 858// type from the various singletons then this will diverge. 859type prebuiltBootclasspathFragmentModule struct { 860 BootclasspathFragmentModule 861 prebuilt android.Prebuilt 862 863 // Additional prebuilt specific properties. 864 prebuiltProperties prebuiltBootclasspathFragmentProperties 865} 866 867func (module *prebuiltBootclasspathFragmentModule) Prebuilt() *android.Prebuilt { 868 return &module.prebuilt 869} 870 871func (module *prebuiltBootclasspathFragmentModule) Name() string { 872 return module.prebuilt.Name(module.ModuleBase.Name()) 873} 874 875// produceHiddenAPIOutput returns a path to the prebuilt all-flags.csv or nil if none is specified. 876func (module *prebuiltBootclasspathFragmentModule) produceHiddenAPIOutput(ctx android.ModuleContext, contents []android.Module, input HiddenAPIFlagInput) *HiddenAPIOutput { 877 pathForOptionalSrc := func(src *string) android.Path { 878 if src == nil { 879 // TODO(b/179354495): Fail if this is not provided once prebuilts have been updated. 880 return nil 881 } 882 return android.PathForModuleSrc(ctx, *src) 883 } 884 885 // Retrieve the dex files directly from the content modules. They in turn should retrieve the 886 // encoded dex jars from the prebuilt .apex files. 887 encodedBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, contents) 888 889 output := HiddenAPIOutput{ 890 HiddenAPIFlagOutput: HiddenAPIFlagOutput{ 891 StubFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Stub_flags), 892 AnnotationFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Annotation_flags), 893 MetadataPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Metadata), 894 IndexPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.Index), 895 AllFlagsPath: pathForOptionalSrc(module.prebuiltProperties.Hidden_api.All_flags), 896 }, 897 EncodedBootDexFilesByModule: encodedBootDexJarsByModule, 898 } 899 900 return &output 901} 902 903// produceBootImageFiles extracts the boot image files from the APEX if available. 904func (module *prebuiltBootclasspathFragmentModule) produceBootImageFiles(ctx android.ModuleContext, imageConfig *bootImageConfig) bootImageFilesByArch { 905 if !shouldCopyBootFilesToPredefinedLocations(ctx, imageConfig) { 906 return nil 907 } 908 909 var deapexerModule android.Module 910 ctx.VisitDirectDeps(func(to android.Module) { 911 tag := ctx.OtherModuleDependencyTag(to) 912 // Save away the `deapexer` module on which this depends, if any. 913 if tag == android.DeapexerTag { 914 if deapexerModule != nil { 915 ctx.ModuleErrorf("Ambiguous duplicate deapexer module dependencies %q and %q", 916 deapexerModule.Name(), to.Name()) 917 } 918 deapexerModule = to 919 } 920 }) 921 922 if deapexerModule == nil { 923 // This should never happen as a variant for a prebuilt_apex is only created if the 924 // deapexer module has been configured to export the dex implementation jar for this module. 925 ctx.ModuleErrorf("internal error: module does not depend on a `deapexer` module") 926 return nil 927 } 928 929 di := ctx.OtherModuleProvider(deapexerModule, android.DeapexerProvider).(android.DeapexerInfo) 930 files := bootImageFilesByArch{} 931 for _, variant := range imageConfig.apexVariants() { 932 arch := variant.target.Arch.ArchType 933 for _, toPath := range variant.imagesDeps { 934 apexRelativePath := apexRootRelativePathToBootImageFile(arch, toPath.Base()) 935 // Get the path to the file that the deapexer extracted from the prebuilt apex file. 936 fromPath := di.PrebuiltExportPath(apexRelativePath) 937 938 // Return the toPath as the calling code expects the paths in the returned map to be the 939 // paths predefined in the bootImageConfig. 940 files[arch] = append(files[arch], toPath) 941 942 // Copy the file to the predefined location. 943 ctx.Build(pctx, android.BuildParams{ 944 Rule: android.Cp, 945 Input: fromPath, 946 Output: toPath, 947 }) 948 } 949 } 950 951 // Build the boot image files for the host variants. These are built from the dex files provided 952 // by the contents of this module as prebuilt versions of the host boot image files are not 953 // available, i.e. there is no host specific prebuilt apex containing them. This has to be built 954 // without a profile as the prebuilt modules do not provide a profile. 955 buildBootImageVariantsForBuildOs(ctx, imageConfig, nil) 956 957 return files 958} 959 960var _ commonBootclasspathFragment = (*prebuiltBootclasspathFragmentModule)(nil) 961 962// createBootImageTag creates the tag to uniquely identify the boot image file among all of the 963// files that a module requires from the prebuilt .apex file. 964func createBootImageTag(arch android.ArchType, baseName string) string { 965 tag := fmt.Sprintf(".bootimage-%s-%s", arch, baseName) 966 return tag 967} 968 969// RequiredFilesFromPrebuiltApex returns the list of all files the prebuilt_bootclasspath_fragment 970// requires from a prebuilt .apex file. 971// 972// If there is no image config associated with this fragment then it returns nil. Otherwise, it 973// returns the files that are listed in the image config. 974func (module *prebuiltBootclasspathFragmentModule) RequiredFilesFromPrebuiltApex(ctx android.BaseModuleContext) []string { 975 imageConfig := module.getImageConfig(ctx) 976 if imageConfig != nil { 977 // Add the boot image files, e.g. .art, .oat and .vdex files. 978 files := []string{} 979 for _, variant := range imageConfig.apexVariants() { 980 arch := variant.target.Arch.ArchType 981 for _, path := range variant.imagesDeps.Paths() { 982 base := path.Base() 983 files = append(files, apexRootRelativePathToBootImageFile(arch, base)) 984 } 985 } 986 return files 987 } 988 return nil 989} 990 991func apexRootRelativePathToBootImageFile(arch android.ArchType, base string) string { 992 return filepath.Join("javalib", arch.String(), base) 993} 994 995var _ android.RequiredFilesFromPrebuiltApex = (*prebuiltBootclasspathFragmentModule)(nil) 996 997func prebuiltBootclasspathFragmentFactory() android.Module { 998 m := &prebuiltBootclasspathFragmentModule{} 999 m.AddProperties(&m.properties, &m.prebuiltProperties) 1000 // This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs 1001 // array. 1002 android.InitPrebuiltModule(m, &[]string{"placeholder"}) 1003 android.InitApexModule(m) 1004 android.InitSdkAwareModule(m) 1005 android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon) 1006 1007 // Initialize the contents property from the image_name. 1008 android.AddLoadHook(m, func(ctx android.LoadHookContext) { 1009 bootclasspathFragmentInitContentsFromImage(ctx, &m.BootclasspathFragmentModule) 1010 }) 1011 return m 1012} 1013