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 Hidden_api 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 SkipDexpreoptBootJars(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 bootImageConfig := b.getImageConfig(ctx) 133 addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathBootJarDepTag) 134 135 // Add dependencies on all the apex jars. 136 apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 137 addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) 138 139 // Add dependencies on all the fragments. 140 b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) 141} 142 143func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { 144 for i := 0; i < modules.Len(); i++ { 145 apex := modules.Apex(i) 146 name := modules.Jar(i) 147 148 addDependencyOntoApexModulePair(ctx, apex, name, tag) 149 } 150} 151 152// GenerateSingletonBuildActions does nothing and must never do anything. 153// 154// This module only implements android.SingletonModule so that it can implement 155// android.SingletonMakeVarsProvider. 156func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) { 157 // Keep empty 158} 159 160func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) { 161 d.generateHiddenApiMakeVars(ctx) 162} 163 164func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 165 // Gather all the dependencies from the art, platform, and apex boot jars. 166 artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) 167 platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag) 168 apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag) 169 170 // Concatenate them all, in order as they would appear on the bootclasspath. 171 var allModules []android.Module 172 allModules = append(allModules, artModules...) 173 allModules = append(allModules, platformModules...) 174 allModules = append(allModules, apexModules...) 175 b.configuredModules = allModules 176 177 // Gather all the fragments dependencies. 178 b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) 179 180 // Check the configuration of the boot modules. 181 // ART modules are checked by the art-bootclasspath-fragment. 182 b.checkPlatformModules(ctx, platformModules) 183 b.checkApexModules(ctx, apexModules) 184 185 b.generateClasspathProtoBuildActions(ctx) 186 187 bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) 188 buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) 189 190 // Nothing to do if skipping the dexpreopt of boot image jars. 191 if SkipDexpreoptBootJars(ctx) { 192 return 193 } 194 195 b.generateBootImageBuildActions(ctx, platformModules, apexModules) 196} 197 198// Generate classpaths.proto config 199func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) { 200 configuredJars := b.configuredJars(ctx) 201 // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH 202 classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) 203 b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) 204} 205 206func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { 207 // Include all non APEX jars 208 jars := b.getImageConfig(ctx).modules 209 210 // Include jars from APEXes that don't populate their classpath proto config. 211 remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 212 for _, fragment := range b.fragments { 213 info := ctx.OtherModuleProvider(fragment, ClasspathFragmentProtoContentInfoProvider).(ClasspathFragmentProtoContentInfo) 214 if info.ClasspathFragmentProtoGenerated { 215 remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents) 216 } 217 } 218 for i := 0; i < remainingJars.Len(); i++ { 219 jars = jars.Append(remainingJars.Apex(i), remainingJars.Jar(i)) 220 } 221 222 return jars 223} 224 225// checkPlatformModules ensures that the non-updatable modules supplied are not part of an 226// apex module. 227func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) { 228 // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here. 229 for _, m := range modules { 230 apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) 231 fromUpdatableApex := apexInfo.Updatable 232 if fromUpdatableApex { 233 // error: this jar is part of an updatable apex 234 ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexVariants) 235 } else { 236 // ok: this jar is part of the platform or a non-updatable apex 237 } 238 } 239} 240 241// checkApexModules ensures that the apex modules supplied are not from the platform. 242func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) { 243 for _, m := range modules { 244 apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) 245 fromUpdatableApex := apexInfo.Updatable 246 if fromUpdatableApex { 247 // ok: this jar is part of an updatable apex 248 } else { 249 name := ctx.OtherModuleName(m) 250 if apexInfo.IsForPlatform() { 251 // If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will 252 // include platform variants of a prebuilt module due to workarounds elsewhere. In that case 253 // do not treat this as an error. 254 // TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment 255 // modules is complete. 256 if !ctx.Config().AlwaysUsePrebuiltSdks() { 257 // error: this jar is part of the platform 258 ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) 259 } 260 } else { 261 // TODO(b/177892522): Treat this as an error. 262 // Cannot do that at the moment because framework-wifi and framework-tethering are in the 263 // PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP. 264 } 265 } 266 } 267} 268 269func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { 270 return defaultBootImageConfig(ctx) 271} 272 273// generateHiddenAPIBuildActions generates all the hidden API related build rules. 274func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { 275 276 // Save the paths to the monolithic files for retrieval via OutputFiles(). 277 b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags 278 b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index 279 b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata 280 281 bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules) 282 283 // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance 284 // optimization that can be used to reduce the incremental build time but as its name suggests it 285 // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. 286 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 287 paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} 288 for _, path := range paths { 289 ctx.Build(pctx, android.BuildParams{ 290 Rule: android.Touch, 291 Output: path, 292 }) 293 } 294 return bootDexJarByModule 295 } 296 297 // Construct a list of ClasspathElement objects from the modules and fragments. 298 classpathElements := CreateClasspathElements(ctx, modules, fragments) 299 300 monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) 301 302 // Extract the classes jars only from those libraries that do not have corresponding fragments as 303 // the fragments will have already provided the flags that are needed. 304 classesJars := monolithicInfo.ClassesJars 305 306 // Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile 307 input := newHiddenAPIFlagInput() 308 309 // Gather stub library information from the dependencies on modules provided by 310 // hiddenAPIComputeMonolithicStubLibModules. 311 input.gatherStubLibInfo(ctx, nil) 312 313 // Use the flag files from this module and all the fragments. 314 input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory 315 316 // Generate the monolithic stub-flags.csv file. 317 stubFlags := hiddenAPISingletonPaths(ctx).stubFlags 318 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets) 319 320 // Generate the annotation-flags.csv file from all the module annotations. 321 annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv") 322 buildRuleToGenerateAnnotationFlags(ctx, "intermediate hidden API flags", classesJars, stubFlags, annotationFlags) 323 324 // Generate the monolithic hiddenapi-flags.csv file. 325 // 326 // Use annotation flags generated directly from the classes jars as well as annotation flag files 327 // provided by prebuilts. 328 allAnnotationFlagFiles := android.Paths{annotationFlags} 329 allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...) 330 allFlags := hiddenAPISingletonPaths(ctx).flags 331 buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{}) 332 333 // Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations 334 // in the source code. 335 intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "metadata-from-classes.csv") 336 buildRuleToGenerateMetadata(ctx, "intermediate hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV) 337 338 // Generate the monolithic hiddenapi-metadata.csv file. 339 // 340 // Use metadata files generated directly from the classes jars as well as metadata files provided 341 // by prebuilts. 342 // 343 // This has the side effect of ensuring that the output file uses | quotes just in case that is 344 // important for the tools that consume the metadata file. 345 allMetadataFlagFiles := android.Paths{intermediateMetadataCSV} 346 allMetadataFlagFiles = append(allMetadataFlagFiles, monolithicInfo.MetadataPaths...) 347 metadataCSV := hiddenAPISingletonPaths(ctx).metadata 348 b.buildRuleMergeCSV(ctx, "monolithic hidden API metadata", allMetadataFlagFiles, metadataCSV) 349 350 // Generate an intermediate monolithic hiddenapi-index.csv file directly from the CSV files in the 351 // classes jars. 352 intermediateIndexCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "index-from-classes.csv") 353 buildRuleToGenerateIndex(ctx, "intermediate hidden API index", classesJars, intermediateIndexCSV) 354 355 // Generate the monolithic hiddenapi-index.csv file. 356 // 357 // Use index files generated directly from the classes jars as well as index files provided 358 // by prebuilts. 359 allIndexFlagFiles := android.Paths{intermediateIndexCSV} 360 allIndexFlagFiles = append(allIndexFlagFiles, monolithicInfo.IndexPaths...) 361 indexCSV := hiddenAPISingletonPaths(ctx).index 362 b.buildRuleMergeCSV(ctx, "monolithic hidden API index", allIndexFlagFiles, indexCSV) 363 364 return bootDexJarByModule 365} 366 367// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for 368// testing. 369func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, classpathElements ClasspathElements) MonolithicHiddenAPIInfo { 370 // Create a temporary input structure in which to collate information provided directly by this 371 // module, either through properties or direct dependencies. 372 temporaryInput := newHiddenAPIFlagInput() 373 374 // Create paths to the flag files specified in the properties. 375 temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api) 376 377 // Create the monolithic info, by starting with the flag files specified on this and then merging 378 // in information from all the fragment dependencies of this. 379 monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements) 380 381 // Store the information for testing. 382 ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo) 383 return monolithicInfo 384} 385 386func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) { 387 rule := android.NewRuleBuilder(pctx, ctx) 388 rule.Command(). 389 BuiltTool("merge_csv"). 390 Flag("--key_field signature"). 391 FlagWithOutput("--output=", outputPath). 392 Inputs(inputPaths) 393 394 rule.Build(desc, desc) 395} 396 397// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g. 398// veridex and run-appcompat. 399func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) { 400 if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { 401 return 402 } 403 // INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. 404 ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) 405} 406 407// generateBootImageBuildActions generates ninja rules related to the boot image creation. 408func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, platformModules, apexModules []android.Module) { 409 // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars 410 // GenerateSingletonBuildActions method as it cannot create it for itself. 411 dexpreopt.GetGlobalSoongConfig(ctx) 412 413 imageConfig := b.getImageConfig(ctx) 414 if imageConfig == nil { 415 return 416 } 417 418 global := dexpreopt.GetGlobalConfig(ctx) 419 if !shouldBuildBootImages(ctx.Config(), global) { 420 return 421 } 422 423 // Generate the framework profile rule 424 bootFrameworkProfileRule(ctx, imageConfig) 425 426 // Copy platform module dex jars to their predefined locations. 427 platformBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, platformModules) 428 copyBootJarsToPredefinedLocations(ctx, platformBootDexJarsByModule, imageConfig.dexPathsByModule) 429 430 // Copy apex module dex jars to their predefined locations. 431 config := GetApexBootConfig(ctx) 432 apexBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, apexModules) 433 copyBootJarsToPredefinedLocations(ctx, apexBootDexJarsByModule, config.dexPathsByModule) 434 435 // Build a profile for the image config and then use that to build the boot image. 436 profile := bootImageProfileRule(ctx, imageConfig) 437 438 // Build boot image files for the android variants. 439 androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) 440 441 // Zip the android variant boot image files up. 442 buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFilesByArch) 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 dumpOatRules(ctx, imageConfig) 448} 449