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