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 "android/soong/android" 19 "android/soong/dexpreopt" 20) 21 22func init() { 23 registerPlatformBootclasspathBuildComponents(android.InitRegistrationContext) 24} 25 26func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) { 27 ctx.RegisterModuleType("platform_bootclasspath", platformBootclasspathFactory) 28} 29 30// The tags used for the dependencies between the platform bootclasspath and any configured boot 31// jars. 32var ( 33 platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} 34 platformBootclasspathBootJarDepTag = bootclasspathDependencyTag{name: "platform-boot-jar"} 35 platformBootclasspathApexBootJarDepTag = bootclasspathDependencyTag{name: "apex-boot-jar"} 36 platformBootclasspathImplLibDepTag = dependencyTag{name: "impl-lib-tag"} 37) 38 39type platformBootclasspathModule struct { 40 android.ModuleBase 41 ClasspathFragmentBase 42 43 properties platformBootclasspathProperties 44 45 // The apex:module pairs obtained from the configured modules. 46 configuredModules []android.Module 47 48 // The apex:module pairs obtained from the fragments. 49 fragments []android.Module 50 51 // Path to the monolithic hiddenapi-flags.csv file. 52 hiddenAPIFlagsCSV android.OutputPath 53 54 // Path to the monolithic hiddenapi-index.csv file. 55 hiddenAPIIndexCSV android.OutputPath 56 57 // Path to the monolithic hiddenapi-unsupported.csv file. 58 hiddenAPIMetadataCSV android.OutputPath 59} 60 61type platformBootclasspathProperties struct { 62 BootclasspathFragmentsDepsProperties 63 64 HiddenAPIFlagFileProperties 65} 66 67func platformBootclasspathFactory() android.Module { 68 m := &platformBootclasspathModule{} 69 m.AddProperties(&m.properties) 70 initClasspathFragment(m, BOOTCLASSPATH) 71 android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) 72 return m 73} 74 75func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) { 76 entries = append(entries, android.AndroidMkEntries{ 77 Class: "FAKE", 78 // Need at least one output file in order for this to take effect. 79 OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV), 80 Include: "$(BUILD_PHONY_PACKAGE)", 81 }) 82 entries = append(entries, b.classpathFragmentBase().androidMkEntries()...) 83 return 84} 85 86func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { 87 // Create a dependency on all_apex_contributions to determine the selected mainline module 88 ctx.AddDependency(ctx.Module(), apexContributionsMetadataDepTag, "all_apex_contributions") 89 90 b.hiddenAPIDepsMutator(ctx) 91 92 if !dexpreopt.IsDex2oatNeeded(ctx) { 93 return 94 } 95 96 // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The 97 // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). 98 dexpreopt.RegisterToolDeps(ctx) 99} 100 101func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { 102 if ctx.Config().DisableHiddenApiChecks() { 103 return 104 } 105 106 // Add dependencies onto the stub lib modules. 107 apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) 108 hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) 109} 110 111func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { 112 // Add dependencies on all the ART jars. 113 global := dexpreopt.GetGlobalConfig(ctx) 114 addDependenciesOntoSelectedBootImageApexes(ctx, "com.android.art") 115 116 var bootImageModuleNames []string 117 118 // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly 119 addDependenciesOntoBootImageModules(ctx, global.ArtApexJars, platformBootclasspathArtBootJarDepTag) 120 bootImageModuleNames = append(bootImageModuleNames, global.ArtApexJars.CopyOfJars()...) 121 122 // Add dependencies on all the non-updatable jars, which are on the platform or in non-updatable 123 // APEXes. 124 platformJars := b.platformJars(ctx) 125 addDependenciesOntoBootImageModules(ctx, platformJars, platformBootclasspathBootJarDepTag) 126 bootImageModuleNames = append(bootImageModuleNames, platformJars.CopyOfJars()...) 127 128 // Add dependencies on all the updatable jars, except the ART jars. 129 apexJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 130 apexes := []string{} 131 for i := 0; i < apexJars.Len(); i++ { 132 apexes = append(apexes, apexJars.Apex(i)) 133 } 134 addDependenciesOntoSelectedBootImageApexes(ctx, android.FirstUniqueStrings(apexes)...) 135 // TODO: b/308174306 - Remove the mechanism of depending on the java_sdk_library(_import) directly 136 addDependenciesOntoBootImageModules(ctx, apexJars, platformBootclasspathApexBootJarDepTag) 137 bootImageModuleNames = append(bootImageModuleNames, apexJars.CopyOfJars()...) 138 139 // Add dependencies on all the fragments. 140 b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) 141 142 for _, bootImageModuleName := range bootImageModuleNames { 143 implLibName := implLibraryModuleName(bootImageModuleName) 144 if ctx.OtherModuleExists(implLibName) { 145 ctx.AddFarVariationDependencies(nil, platformBootclasspathImplLibDepTag, implLibName) 146 } 147 } 148} 149 150func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { 151 for i := 0; i < modules.Len(); i++ { 152 apex := modules.Apex(i) 153 name := modules.Jar(i) 154 155 addDependencyOntoApexModulePair(ctx, apex, name, tag) 156 } 157} 158 159func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { 160 // Gather all the dependencies from the art, platform, and apex boot jars. 161 artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) 162 platformModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathBootJarDepTag) 163 apexModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathApexBootJarDepTag) 164 165 // Concatenate them all, in order as they would appear on the bootclasspath. 166 var allModules []android.Module 167 allModules = append(allModules, artModules...) 168 allModules = append(allModules, platformModules...) 169 allModules = append(allModules, apexModules...) 170 b.configuredModules = allModules 171 172 // Do not add implLibModule to allModules as the impl lib is only used to collect the 173 // transitive source files 174 var implLibModule []android.Module 175 ctx.VisitDirectDepsWithTag(implLibraryTag, func(m android.Module) { 176 implLibModule = append(implLibModule, m) 177 }) 178 179 var transitiveSrcFiles android.Paths 180 for _, module := range append(allModules, implLibModule...) { 181 if depInfo, ok := android.OtherModuleProvider(ctx, module, JavaInfoProvider); ok { 182 transitiveSrcFiles = append(transitiveSrcFiles, depInfo.TransitiveSrcFiles.ToList()...) 183 } 184 } 185 jarArgs := resourcePathsToJarArgs(transitiveSrcFiles) 186 jarArgs = append(jarArgs, "-srcjar") // Move srcfiles to the right package 187 srcjar := android.PathForModuleOut(ctx, ctx.ModuleName()+"-transitive.srcjar") 188 TransformResourcesToJar(ctx, srcjar, jarArgs, transitiveSrcFiles) 189 190 // Gather all the fragments dependencies. 191 b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) 192 193 // Check the configuration of the boot modules. 194 // ART modules are checked by the art-bootclasspath-fragment. 195 b.checkPlatformModules(ctx, platformModules) 196 b.checkApexModules(ctx, apexModules) 197 198 b.generateClasspathProtoBuildActions(ctx) 199 200 bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) 201 buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) 202 203 ctx.SetOutputFiles(android.Paths{b.hiddenAPIFlagsCSV}, "hiddenapi-flags.csv") 204 ctx.SetOutputFiles(android.Paths{b.hiddenAPIIndexCSV}, "hiddenapi-index.csv") 205 ctx.SetOutputFiles(android.Paths{b.hiddenAPIMetadataCSV}, "hiddenapi-metadata.csv") 206 ctx.SetOutputFiles(android.Paths{srcjar}, ".srcjar") 207} 208 209// Generate classpaths.proto config 210func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) { 211 configuredJars := b.configuredJars(ctx) 212 // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH 213 classpathJars := configuredJarListToClasspathJars(ctx, configuredJars, BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) 214 b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, configuredJars, classpathJars) 215 b.classpathFragmentBase().installClasspathProto(ctx) 216} 217 218func (b *platformBootclasspathModule) configuredJars(ctx android.ModuleContext) android.ConfiguredJarList { 219 // Include all non APEX jars 220 jars := b.platformJars(ctx) 221 222 // Include jars from APEXes that don't populate their classpath proto config. 223 remainingJars := dexpreopt.GetGlobalConfig(ctx).ApexBootJars 224 for _, fragment := range b.fragments { 225 info, _ := android.OtherModuleProvider(ctx, fragment, ClasspathFragmentProtoContentInfoProvider) 226 if info.ClasspathFragmentProtoGenerated { 227 remainingJars = remainingJars.RemoveList(info.ClasspathFragmentProtoContents) 228 } 229 } 230 for i := 0; i < remainingJars.Len(); i++ { 231 jars = jars.Append(remainingJars.Apex(i), remainingJars.Jar(i)) 232 } 233 234 return jars 235} 236 237func (b *platformBootclasspathModule) platformJars(ctx android.PathContext) android.ConfiguredJarList { 238 global := dexpreopt.GetGlobalConfig(ctx) 239 return global.BootJars.RemoveList(global.ArtApexJars) 240} 241 242// checkPlatformModules ensures that the non-updatable modules supplied are not part of an 243// apex module. 244func (b *platformBootclasspathModule) checkPlatformModules(ctx android.ModuleContext, modules []android.Module) { 245 // TODO(satayev): change this check to only allow core-icu4j, all apex jars should not be here. 246 for _, m := range modules { 247 apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) 248 fromUpdatableApex := apexInfo.Updatable 249 if fromUpdatableApex { 250 // error: this jar is part of an updatable apex 251 ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the platform bootclasspath", ctx.OtherModuleName(m), apexInfo.InApexVariants) 252 } else { 253 // ok: this jar is part of the platform or a non-updatable apex 254 } 255 } 256} 257 258// checkApexModules ensures that the apex modules supplied are not from the platform. 259func (b *platformBootclasspathModule) checkApexModules(ctx android.ModuleContext, modules []android.Module) { 260 for _, m := range modules { 261 apexInfo, _ := android.OtherModuleProvider(ctx, m, android.ApexInfoProvider) 262 fromUpdatableApex := apexInfo.Updatable 263 if fromUpdatableApex { 264 // ok: this jar is part of an updatable apex 265 } else { 266 name := ctx.OtherModuleName(m) 267 if apexInfo.IsForPlatform() { 268 // If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will 269 // include platform variants of a prebuilt module due to workarounds elsewhere. In that case 270 // do not treat this as an error. 271 // TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment 272 // modules is complete. 273 if !ctx.Config().AlwaysUsePrebuiltSdks() { 274 // error: this jar is part of the platform 275 ctx.ModuleErrorf("module %q from platform is not allowed in the apex boot jars list", name) 276 } 277 } else { 278 // TODO(b/177892522): Treat this as an error. 279 // Cannot do that at the moment because framework-wifi and framework-tethering are in the 280 // PRODUCT_APEX_BOOT_JARS but not marked as updatable in AOSP. 281 } 282 } 283 } 284} 285 286// generateHiddenAPIBuildActions generates all the hidden API related build rules. 287func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { 288 createEmptyHiddenApiFiles := func() { 289 paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} 290 for _, path := range paths { 291 ctx.Build(pctx, android.BuildParams{ 292 Rule: android.Touch, 293 Output: path, 294 }) 295 } 296 } 297 298 // Save the paths to the monolithic files for retrieval via OutputFiles(). 299 b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags 300 b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index 301 b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata 302 303 bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules) 304 305 // Don't run any hiddenapi rules if hidden api checks are disabled. This is a performance 306 // optimization that can be used to reduce the incremental build time but as its name suggests it 307 // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. 308 if ctx.Config().DisableHiddenApiChecks() { 309 createEmptyHiddenApiFiles() 310 return bootDexJarByModule 311 } 312 313 // Construct a list of ClasspathElement objects from the modules and fragments. 314 classpathElements := CreateClasspathElements(ctx, modules, fragments) 315 316 monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) 317 318 // Extract the classes jars only from those libraries that do not have corresponding fragments as 319 // the fragments will have already provided the flags that are needed. 320 classesJars := monolithicInfo.ClassesJars 321 322 if len(classesJars) == 0 { 323 // This product does not include any monolithic jars. Monolithic hiddenapi flag generation is not required. 324 // However, generate an empty file so that the dist tags in f/b/boot/Android.bp can be resolved, and `m dist` works. 325 createEmptyHiddenApiFiles() 326 return bootDexJarByModule 327 } 328 329 // Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile 330 input := newHiddenAPIFlagInput() 331 332 // Gather stub library information from the dependencies on modules provided by 333 // hiddenAPIComputeMonolithicStubLibModules. 334 input.gatherStubLibInfo(ctx, nil) 335 336 // Use the flag files from this module and all the fragments. 337 input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory 338 339 // Generate the monolithic stub-flags.csv file. 340 stubFlags := hiddenAPISingletonPaths(ctx).stubFlags 341 buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagSubsets) 342 343 // Generate the annotation-flags.csv file from all the module annotations. 344 annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv") 345 buildRuleToGenerateAnnotationFlags(ctx, "intermediate hidden API flags", classesJars, stubFlags, annotationFlags) 346 347 // Generate the monolithic hiddenapi-flags.csv file. 348 // 349 // Use annotation flags generated directly from the classes jars as well as annotation flag files 350 // provided by prebuilts. 351 allAnnotationFlagFiles := android.Paths{annotationFlags} 352 allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...) 353 allFlags := hiddenAPISingletonPaths(ctx).flags 354 buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.FlagSubsets, android.OptionalPath{}) 355 356 // Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations 357 // in the source code. 358 intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "metadata-from-classes.csv") 359 buildRuleToGenerateMetadata(ctx, "intermediate hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV) 360 361 // Generate the monolithic hiddenapi-metadata.csv file. 362 // 363 // Use metadata files generated directly from the classes jars as well as metadata files provided 364 // by prebuilts. 365 // 366 // This has the side effect of ensuring that the output file uses | quotes just in case that is 367 // important for the tools that consume the metadata file. 368 allMetadataFlagFiles := android.Paths{intermediateMetadataCSV} 369 allMetadataFlagFiles = append(allMetadataFlagFiles, monolithicInfo.MetadataPaths...) 370 metadataCSV := hiddenAPISingletonPaths(ctx).metadata 371 b.buildRuleMergeCSV(ctx, "monolithic hidden API metadata", allMetadataFlagFiles, metadataCSV) 372 373 // Generate an intermediate monolithic hiddenapi-index.csv file directly from the CSV files in the 374 // classes jars. 375 intermediateIndexCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "index-from-classes.csv") 376 buildRuleToGenerateIndex(ctx, "intermediate hidden API index", classesJars, intermediateIndexCSV) 377 378 // Generate the monolithic hiddenapi-index.csv file. 379 // 380 // Use index files generated directly from the classes jars as well as index files provided 381 // by prebuilts. 382 allIndexFlagFiles := android.Paths{intermediateIndexCSV} 383 allIndexFlagFiles = append(allIndexFlagFiles, monolithicInfo.IndexPaths...) 384 indexCSV := hiddenAPISingletonPaths(ctx).index 385 b.buildRuleMergeCSV(ctx, "monolithic hidden API index", allIndexFlagFiles, indexCSV) 386 387 return bootDexJarByModule 388} 389 390// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for 391// testing. 392func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, classpathElements ClasspathElements) MonolithicHiddenAPIInfo { 393 // Create a temporary input structure in which to collate information provided directly by this 394 // module, either through properties or direct dependencies. 395 temporaryInput := newHiddenAPIFlagInput() 396 397 // Create paths to the flag files specified in the properties. 398 temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.HiddenAPIFlagFileProperties) 399 400 // Create the monolithic info, by starting with the flag files specified on this and then merging 401 // in information from all the fragment dependencies of this. 402 monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements) 403 404 // Store the information for testing. 405 android.SetProvider(ctx, MonolithicHiddenAPIInfoProvider, monolithicInfo) 406 return monolithicInfo 407} 408 409func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) { 410 rule := android.NewRuleBuilder(pctx, ctx) 411 rule.Command(). 412 BuiltTool("merge_csv"). 413 Flag("--key_field signature"). 414 FlagWithOutput("--output=", outputPath). 415 Inputs(inputPaths) 416 417 rule.Build(desc, desc) 418} 419