1// Copyright 2021 Google Inc. All rights reserved. 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 20 "android/soong/android" 21 "android/soong/dexpreopt" 22) 23 24func init() { 25 registerPlatformBootclasspathBuildComponents(android.InitRegistrationContext) 26} 27 28func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) { 29 ctx.RegisterSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory) 30} 31 32// The tags used for the dependencies between the platform bootclasspath and any configured boot 33// jars. 34var ( 35 platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} 36 platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"} 37 platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"} 38) 39 40type platformBootclasspathModule struct { 41 android.SingletonModuleBase 42 ClasspathFragmentBase 43 44 properties platformBootclasspathProperties 45 46 // The apex:module pairs obtained from the configured modules. 47 configuredModules []android.Module 48 49 // The apex:module pairs obtained from the fragments. 50 fragments []android.Module 51 52 // Path to the monolithic hiddenapi-flags.csv file. 53 hiddenAPIFlagsCSV android.OutputPath 54 55 // Path to the monolithic hiddenapi-index.csv file. 56 hiddenAPIIndexCSV android.OutputPath 57 58 // Path to the monolithic hiddenapi-unsupported.csv file. 59 hiddenAPIMetadataCSV android.OutputPath 60} 61 62type platformBootclasspathProperties struct { 63 BootclasspathFragmentsDepsProperties 64 65 HiddenAPIFlagFileProperties 66} 67 68func platformBootclasspathFactory() android.SingletonModule { 69 m := &platformBootclasspathModule{} 70 m.AddProperties(&m.properties) 71 initClasspathFragment(m, BOOTCLASSPATH) 72 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 73 return m 74} 75 76var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil) 77 78func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) { 79 entries = append(entries, android.AndroidMkEntries{ 80 Class: "FAKE", 81 // Need at least one output file in order for this to take effect. 82 OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV), 83 Include: "$(BUILD_PHONY_PACKAGE)", 84 }) 85 entries = append(entries, b.classpathFragmentBase().androidMkEntries()...) 86 return 87} 88 89// Make the hidden API files available from the platform-bootclasspath module. 90func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) { 91 switch tag { 92 case "hiddenapi-flags.csv": 93 return android.Paths{b.hiddenAPIFlagsCSV}, nil 94 case "hiddenapi-index.csv": 95 return android.Paths{b.hiddenAPIIndexCSV}, nil 96 case "hiddenapi-metadata.csv": 97 return android.Paths{b.hiddenAPIMetadataCSV}, nil 98 } 99 100 return nil, fmt.Errorf("unknown tag %s", tag) 101} 102 103func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { 104 b.hiddenAPIDepsMutator(ctx) 105 106 if !dexpreopt.IsDex2oatNeeded(ctx) { 107 return 108 } 109 110 // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The 111 // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). 112 dexpreopt.RegisterToolDeps(ctx) 113} 114 115func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { 116 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 117 return 118 } 119 120 // Add dependencies onto the stub lib modules. 121 apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) 122 hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) 123} 124 125func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { 126 // Add dependencies on all the modules configured in the "art" boot image. 127 artImageConfig := genBootImageConfigs(ctx)[artBootImageName] 128 addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag) 129 130 // Add dependencies on all the non-updatable module configured in the "boot" boot image. That does 131 // not include modules configured in the "art" boot image. 132 addDependenciesOntoBootImageModules(ctx, b.platformJars(ctx), platformBootclasspathBootJarDepTag) 133 134 // Add dependencies on all the apex jars. 135 apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 136 addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) 137 138 // Add dependencies on all the fragments. 139 b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) 140} 141 142func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { 143 for i := 0; i < modules.Len(); i++ { 144 apex := modules.Apex(i) 145 name := modules.Jar(i) 146 147 addDependencyOntoApexModulePair(ctx, apex, name, tag) 148 } 149} 150 151// GenerateSingletonBuildActions does nothing and must never do anything. 152// 153// This module only implements android.SingletonModule so that it can implement 154// android.SingletonMakeVarsProvider. 155func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) { 156 // Keep empty 157} 158 159func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) { 160 d.generateHiddenApiMakeVars(ctx) 161} 162 163func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 164 // Gather all the dependencies from the art, platform, and apex boot jars. 165 artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) 166 platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag) 167 apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag) 168 169 // Concatenate them all, in order as they would appear on the bootclasspath. 170 var allModules []android.Module 171 allModules = append(allModules, artModules...) 172 allModules = append(allModules, platformModules...) 173 allModules = append(allModules, apexModules...) 174 b.configuredModules = allModules 175 176 // Gather all the fragments dependencies. 177 b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) 178 179 // Check the configuration of the boot modules. 180 // ART modules are checked by the art-bootclasspath-fragment. 181 b.checkPlatformModules(ctx, platformModules) 182 b.checkApexModules(ctx, apexModules) 183 184 b.generateClasspathProtoBuildActions(ctx) 185 186 bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) 187 buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) 188 189 b.generateBootImageBuildActions(ctx) 190 b.copyApexBootJarsForAppsDexpreopt(ctx, apexModules) 191} 192 193// Generate classpaths.proto config 194func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) { 195 configuredJars := b.configuredJars(ctx) 196 // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH 197 classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) 198 b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) 199} 200 201func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { 202 // Include all non APEX jars 203 jars := b.platformJars(ctx) 204 205 // Include jars from APEXes that don't populate their classpath proto config. 206 remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 207 for _, fragment := range b.fragments { 208 info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo) 209 if info.ClasspathFragmentProtoGenerated { 210 remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents) 211 } 212 } 213 for i := 0; i < remainingJars.Len(); i++ { 214 jars = jars.Append(remainingJars.Apex(i), remainingJars.Jar(i)) 215 } 216 217 return jars 218} 219 220func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList { 221 return defaultBootImageConfig(ctx).modules.RemoveList(artBootImageConfig(ctx).modules) 222} 223 224// checkPlatformModules ensures that the non-updatable modules supplied are not part of an 225// apex module. 226func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) { 227 // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here. 228 for _, m := range modules { 229 apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) 230 fromUpdatableApex := apexInfo.Updatable 231 if fromUpdatableApex { 232 // error: this jar is part of an updatable apex 233 ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.InApexVariants) 234 } else { 235 // ok: this jar is part of the platform or a non-updatable apex 236 } 237 } 238} 239 240// checkApexModules ensures that the apex modules supplied are not from the platform. 241func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) { 242 for _, m := range modules { 243 apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) 244 fromUpdatableApex := apexInfo.Updatable 245 if fromUpdatableApex { 246 // ok: this jar is part of an updatable apex 247 } else { 248 name := ctx.OtherModuleName(m) 249 if apexInfo.IsForPlatform() { 250 // If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will 251 // include platform variants of a prebuilt module due to workarounds elsewhere. In that case 252 // do not treat this as an error. 253 // TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment 254 // modules is complete. 255 if !ctx.Config().AlwaysUsePrebuiltSdks() { 256 // error: this jar is part of the platform 257 ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) 258 } 259 } else { 260 // TODO(b/177892522): Treat this as an error. 261 // Cannot do that at the moment because framework-wifi and framework-tethering are in the 262 // PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP. 263 } 264 } 265 } 266} 267 268// generateHiddenAPIBuildActions generates all the hidden API related build rules. 269func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { 270 271 // Save the paths to the monolithic files for retrieval via OutputFiles(). 272 b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags 273 b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index 274 b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata 275 276 bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules) 277 278 // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance 279 // optimization that can be used to reduce the incremental build time but as its name suggests it 280 // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. 281 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 282 paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} 283 for _, path := range paths { 284 ctx.Build(pctx, android.BuildParams{ 285 Rule: android.Touch, 286 Output: path, 287 }) 288 } 289 return bootDexJarByModule 290 } 291 292 // Construct a list of ClasspathElement objects from the modules and fragments. 293 classpathElements := CreateClasspathElements(ctx, modules, fragments) 294 295 monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) 296 297 // Extract the classes jars only from those libraries that do not have corresponding fragments as 298 // the fragments will have already provided the flags that are needed. 299 classesJars := monolithicInfo.ClassesJars 300 301 // Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile 302 input := newHiddenAPIFlagInput() 303 304 // Gather stub library information from the dependencies on modules provided by 305 // hiddenAPIComputeMonolithicStubLibModules. 306 input.gatherStubLibInfo(ctx, nil) 307 308 // Use the flag files from this module and all the fragments. 309 input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory 310 311 // Generate the monolithic stub-flags.csv file. 312 stubFlags := hiddenAPISingletonPaths(ctx).stubFlags 313 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets) 314 315 // Generate the annotation-flags.csv file from all the module annotations. 316 annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv") 317 buildRuleToGenerateAnnotationFlags(ctx, "intermediate hidden API flags", classesJars, stubFlags, annotationFlags) 318 319 // Generate the monolithic hiddenapi-flags.csv file. 320 // 321 // Use annotation flags generated directly from the classes jars as well as annotation flag files 322 // provided by prebuilts. 323 allAnnotationFlagFiles := android.Paths{annotationFlags} 324 allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...) 325 allFlags := hiddenAPISingletonPaths(ctx).flags 326 buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{}) 327 328 // Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations 329 // in the source code. 330 intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "metadata-from-classes.csv") 331 buildRuleToGenerateMetadata(ctx, "intermediate hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV) 332 333 // Generate the monolithic hiddenapi-metadata.csv file. 334 // 335 // Use metadata files generated directly from the classes jars as well as metadata files provided 336 // by prebuilts. 337 // 338 // This has the side effect of ensuring that the output file uses | quotes just in case that is 339 // important for the tools that consume the metadata file. 340 allMetadataFlagFiles := android.Paths{intermediateMetadataCSV} 341 allMetadataFlagFiles = append(allMetadataFlagFiles, monolithicInfo.MetadataPaths...) 342 metadataCSV := hiddenAPISingletonPaths(ctx).metadata 343 b.buildRuleMergeCSV(ctx, "monolithic hidden API metadata", allMetadataFlagFiles, metadataCSV) 344 345 // Generate an intermediate monolithic hiddenapi-index.csv file directly from the CSV files in the 346 // classes jars. 347 intermediateIndexCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "index-from-classes.csv") 348 buildRuleToGenerateIndex(ctx, "intermediate hidden API index", classesJars, intermediateIndexCSV) 349 350 // Generate the monolithic hiddenapi-index.csv file. 351 // 352 // Use index files generated directly from the classes jars as well as index files provided 353 // by prebuilts. 354 allIndexFlagFiles := android.Paths{intermediateIndexCSV} 355 allIndexFlagFiles = append(allIndexFlagFiles, monolithicInfo.IndexPaths...) 356 indexCSV := hiddenAPISingletonPaths(ctx).index 357 b.buildRuleMergeCSV(ctx, "monolithic hidden API index", allIndexFlagFiles, indexCSV) 358 359 return bootDexJarByModule 360} 361 362// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for 363// testing. 364func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, classpathElements ClasspathElements) MonolithicHiddenAPIInfo { 365 // Create a temporary input structure in which to collate information provided directly by this 366 // module, either through properties or direct dependencies. 367 temporaryInput := newHiddenAPIFlagInput() 368 369 // Create paths to the flag files specified in the properties. 370 temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.HiddenAPIFlagFileProperties) 371 372 // Create the monolithic info, by starting with the flag files specified on this and then merging 373 // in information from all the fragment dependencies of this. 374 monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements) 375 376 // Store the information for testing. 377 ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo) 378 return monolithicInfo 379} 380 381func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) { 382 rule := android.NewRuleBuilder(pctx, ctx) 383 rule.Command(). 384 BuiltTool("merge_csv"). 385 Flag("--key_field signature"). 386 FlagWithOutput("--output=", outputPath). 387 Inputs(inputPaths) 388 389 rule.Build(desc, desc) 390} 391 392// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g. 393// veridex and run-appcompat. 394func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) { 395 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 396 return 397 } 398 // INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. 399 ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) 400} 401 402// generateBootImageBuildActions generates ninja rules related to the boot image creation. 403func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext) { 404 // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars 405 // GenerateSingletonBuildActions method as it cannot create it for itself. 406 dexpreopt.GetGlobalSoongConfig(ctx) 407 408 global := dexpreopt.GetGlobalConfig(ctx) 409 if !shouldBuildBootImages(ctx.Config(), global) { 410 return 411 } 412 413 frameworkBootImageConfig := defaultBootImageConfig(ctx) 414 bootFrameworkProfileRule(ctx, frameworkBootImageConfig) 415 b.generateBootImage(ctx, frameworkBootImageName) 416 b.generateBootImage(ctx, mainlineBootImageName) 417 dumpOatRules(ctx, frameworkBootImageConfig) 418} 419 420func (b *platformBootclasspathModule) generateBootImage(ctx android.ModuleContext, imageName string) { 421 imageConfig := genBootImageConfigs(ctx)[imageName] 422 423 modules := b.getModulesForImage(ctx, imageConfig) 424 425 // Copy module dex jars to their predefined locations. 426 bootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, modules) 427 copyBootJarsToPredefinedLocations(ctx, bootDexJarsByModule, imageConfig.dexPathsByModule) 428 429 // Build a profile for the image config and then use that to build the boot image. 430 profile := bootImageProfileRule(ctx, imageConfig) 431 432 // If dexpreopt of boot image jars should be skipped, generate only a profile. 433 global := dexpreopt.GetGlobalConfig(ctx) 434 if global.DisablePreoptBootImages { 435 return 436 } 437 438 // Build boot image files for the android variants. 439 androidBootImageFiles := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) 440 441 // Zip the android variant boot image files up. 442 buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFiles.byArch) 443 444 // Build boot image files for the host variants. There are use directly by ART host side tests. 445 buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) 446} 447 448// Copy apex module dex jars to their predefined locations. They will be used for dexpreopt for apps. 449func (b *platformBootclasspathModule) copyApexBootJarsForAppsDexpreopt(ctx android.ModuleContext, apexModules []android.Module) { 450 config := GetApexBootConfig(ctx) 451 apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules) 452 copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule) 453} 454 455func (b *platformBootclasspathModule) getModulesForImage(ctx android.ModuleContext, imageConfig *bootImageConfig) []android.Module { 456 modules := make([]android.Module, 0, imageConfig.modules.Len()) 457 for i := 0; i < imageConfig.modules.Len(); i++ { 458 found := false 459 for _, module := range b.configuredModules { 460 name := android.RemoveOptionalPrebuiltPrefix(module.Name()) 461 if name == imageConfig.modules.Jar(i) { 462 modules = append(modules, module) 463 found = true 464 break 465 } 466 } 467 if !found && !ctx.Config().AllowMissingDependencies() { 468 ctx.ModuleErrorf( 469 "Boot image '%s' module '%s' not added as a dependency of platform_bootclasspath", 470 imageConfig.name, 471 imageConfig.modules.Jar(i)) 472 return []android.Module{} 473 } 474 } 475 return modules 476} 477