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