diff options
Diffstat (limited to 'java/platform_bootclasspath.go')
-rw-r--r-- | java/platform_bootclasspath.go | 435 |
1 files changed, 435 insertions, 0 deletions
diff --git a/java/platform_bootclasspath.go b/java/platform_bootclasspath.go new file mode 100644 index 000000000..10739b015 --- /dev/null +++ b/java/platform_bootclasspath.go @@ -0,0 +1,435 @@ +// Copyright 2021 Google Inc. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +package java + +import ( + "fmt" + + "android/soong/android" + "android/soong/dexpreopt" +) + +func init() { + registerPlatformBootclasspathBuildComponents(android.InitRegistrationContext) +} + +func registerPlatformBootclasspathBuildComponents(ctx android.RegistrationContext) { + ctx.RegisterSingletonModuleType("platform_bootclasspath", platformBootclasspathFactory) +} + +// The tags used for the dependencies between the platform bootclasspath and any configured boot +// jars. +var ( + platformBootclasspathArtBootJarDepTag = bootclasspathDependencyTag{name: "art-boot-jar"} + platformBootclasspathNonUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "non-updatable-boot-jar"} + platformBootclasspathUpdatableBootJarDepTag = bootclasspathDependencyTag{name: "updatable-boot-jar"} +) + +type platformBootclasspathModule struct { + android.SingletonModuleBase + ClasspathFragmentBase + + properties platformBootclasspathProperties + + // The apex:module pairs obtained from the configured modules. + configuredModules []android.Module + + // The apex:module pairs obtained from the fragments. + fragments []android.Module + + // Path to the monolithic hiddenapi-flags.csv file. + hiddenAPIFlagsCSV android.OutputPath + + // Path to the monolithic hiddenapi-index.csv file. + hiddenAPIIndexCSV android.OutputPath + + // Path to the monolithic hiddenapi-unsupported.csv file. + hiddenAPIMetadataCSV android.OutputPath +} + +type platformBootclasspathProperties struct { + BootclasspathFragmentsDepsProperties + + Hidden_api HiddenAPIFlagFileProperties +} + +func platformBootclasspathFactory() android.SingletonModule { + m := &platformBootclasspathModule{} + m.AddProperties(&m.properties) + // TODO(satayev): split apex jars into separate configs. + initClasspathFragment(m, BOOTCLASSPATH) + android.InitAndroidArchModule(m, android.DeviceSupported, android.MultilibCommon) + return m +} + +var _ android.OutputFileProducer = (*platformBootclasspathModule)(nil) + +func (b *platformBootclasspathModule) AndroidMkEntries() (entries []android.AndroidMkEntries) { + entries = append(entries, android.AndroidMkEntries{ + Class: "FAKE", + // Need at least one output file in order for this to take effect. + OutputFile: android.OptionalPathForPath(b.hiddenAPIFlagsCSV), + Include: "$(BUILD_PHONY_PACKAGE)", + }) + entries = append(entries, b.classpathFragmentBase().androidMkEntries()...) + return +} + +// Make the hidden API files available from the platform-bootclasspath module. +func (b *platformBootclasspathModule) OutputFiles(tag string) (android.Paths, error) { + switch tag { + case "hiddenapi-flags.csv": + return android.Paths{b.hiddenAPIFlagsCSV}, nil + case "hiddenapi-index.csv": + return android.Paths{b.hiddenAPIIndexCSV}, nil + case "hiddenapi-metadata.csv": + return android.Paths{b.hiddenAPIMetadataCSV}, nil + } + + return nil, fmt.Errorf("unknown tag %s", tag) +} + +func (b *platformBootclasspathModule) DepsMutator(ctx android.BottomUpMutatorContext) { + b.hiddenAPIDepsMutator(ctx) + + if SkipDexpreoptBootJars(ctx) { + return + } + + // Add a dependency onto the dex2oat tool which is needed for creating the boot image. The + // path is retrieved from the dependency by GetGlobalSoongConfig(ctx). + dexpreopt.RegisterToolDeps(ctx) +} + +func (b *platformBootclasspathModule) hiddenAPIDepsMutator(ctx android.BottomUpMutatorContext) { + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + + // Add dependencies onto the stub lib modules. + apiLevelToStubLibModules := hiddenAPIComputeMonolithicStubLibModules(ctx.Config()) + hiddenAPIAddStubLibDependencies(ctx, apiLevelToStubLibModules) +} + +func (b *platformBootclasspathModule) BootclasspathDepsMutator(ctx android.BottomUpMutatorContext) { + // Add dependencies on all the modules configured in the "art" boot image. + artImageConfig := genBootImageConfigs(ctx)[artBootImageName] + addDependenciesOntoBootImageModules(ctx, artImageConfig.modules, platformBootclasspathArtBootJarDepTag) + + // Add dependencies on all the non-updatable module configured in the "boot" boot image. That does + // not include modules configured in the "art" boot image. + bootImageConfig := b.getImageConfig(ctx) + addDependenciesOntoBootImageModules(ctx, bootImageConfig.modules, platformBootclasspathNonUpdatableBootJarDepTag) + + // Add dependencies on all the updatable modules. + updatableModules := dexpreopt.GetGlobalConfig(ctx).UpdatableBootJars + addDependenciesOntoBootImageModules(ctx, updatableModules, platformBootclasspathUpdatableBootJarDepTag) + + // Add dependencies on all the fragments. + b.properties.BootclasspathFragmentsDepsProperties.addDependenciesOntoFragments(ctx) +} + +func addDependenciesOntoBootImageModules(ctx android.BottomUpMutatorContext, modules android.ConfiguredJarList, tag bootclasspathDependencyTag) { + for i := 0; i < modules.Len(); i++ { + apex := modules.Apex(i) + name := modules.Jar(i) + + addDependencyOntoApexModulePair(ctx, apex, name, tag) + } +} + +// GenerateSingletonBuildActions does nothing and must never do anything. +// +// This module only implements android.SingletonModule so that it can implement +// android.SingletonMakeVarsProvider. +func (b *platformBootclasspathModule) GenerateSingletonBuildActions(android.SingletonContext) { + // Keep empty +} + +func (d *platformBootclasspathModule) MakeVars(ctx android.MakeVarsContext) { + d.generateHiddenApiMakeVars(ctx) +} + +func (b *platformBootclasspathModule) GenerateAndroidBuildActions(ctx android.ModuleContext) { + // Gather all the dependencies from the art, updatable and non-updatable boot jars. + artModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathArtBootJarDepTag) + nonUpdatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathNonUpdatableBootJarDepTag) + updatableModules := gatherApexModulePairDepsWithTag(ctx, platformBootclasspathUpdatableBootJarDepTag) + + // Concatenate them all, in order as they would appear on the bootclasspath. + var allModules []android.Module + allModules = append(allModules, artModules...) + allModules = append(allModules, nonUpdatableModules...) + allModules = append(allModules, updatableModules...) + b.configuredModules = allModules + + // Gather all the fragments dependencies. + b.fragments = gatherApexModulePairDepsWithTag(ctx, bootclasspathFragmentDepTag) + + // Check the configuration of the boot modules. + // ART modules are checked by the art-bootclasspath-fragment. + b.checkNonUpdatableModules(ctx, nonUpdatableModules) + b.checkUpdatableModules(ctx, updatableModules) + + b.generateClasspathProtoBuildActions(ctx) + + bootDexJarByModule := b.generateHiddenAPIBuildActions(ctx, b.configuredModules, b.fragments) + buildRuleForBootJarsPackageCheck(ctx, bootDexJarByModule) + + // Nothing to do if skipping the dexpreopt of boot image jars. + if SkipDexpreoptBootJars(ctx) { + return + } + + b.generateBootImageBuildActions(ctx, nonUpdatableModules, updatableModules) +} + +// Generate classpaths.proto config +func (b *platformBootclasspathModule) generateClasspathProtoBuildActions(ctx android.ModuleContext) { + // ART and platform boot jars must have a corresponding entry in DEX2OATBOOTCLASSPATH + classpathJars := configuredJarListToClasspathJars(ctx, b.ClasspathFragmentToConfiguredJarList(ctx), BOOTCLASSPATH, DEX2OATBOOTCLASSPATH) + b.classpathFragmentBase().generateClasspathProtoBuildActions(ctx, classpathJars) +} + +func (b *platformBootclasspathModule) ClasspathFragmentToConfiguredJarList(ctx android.ModuleContext) android.ConfiguredJarList { + return b.getImageConfig(ctx).modules +} + +// checkNonUpdatableModules ensures that the non-updatable modules supplied are not part of an +// updatable module. +func (b *platformBootclasspathModule) checkNonUpdatableModules(ctx android.ModuleContext, modules []android.Module) { + for _, m := range modules { + apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) + fromUpdatableApex := apexInfo.Updatable + if fromUpdatableApex { + // error: this jar is part of an updatable apex + ctx.ModuleErrorf("module %q from updatable apexes %q is not allowed in the framework boot image", ctx.OtherModuleName(m), apexInfo.InApexVariants) + } else { + // ok: this jar is part of the platform or a non-updatable apex + } + } +} + +// checkUpdatableModules ensures that the updatable modules supplied are not from the platform. +func (b *platformBootclasspathModule) checkUpdatableModules(ctx android.ModuleContext, modules []android.Module) { + for _, m := range modules { + apexInfo := ctx.OtherModuleProvider(m, android.ApexInfoProvider).(android.ApexInfo) + fromUpdatableApex := apexInfo.Updatable + if fromUpdatableApex { + // ok: this jar is part of an updatable apex + } else { + name := ctx.OtherModuleName(m) + if apexInfo.IsForPlatform() { + // If AlwaysUsePrebuiltSdks() returns true then it is possible that the updatable list will + // include platform variants of a prebuilt module due to workarounds elsewhere. In that case + // do not treat this as an error. + // TODO(b/179354495): Always treat this as an error when migration to bootclasspath_fragment + // modules is complete. + if !ctx.Config().AlwaysUsePrebuiltSdks() { + // error: this jar is part of the platform + ctx.ModuleErrorf("module %q from platform is not allowed in the updatable boot jars list", name) + } + } else { + // TODO(b/177892522): Treat this as an error. + // Cannot do that at the moment because framework-wifi and framework-tethering are in the + // PRODUCT_UPDATABLE_BOOT_JARS but not marked as updatable in AOSP. + } + } + } +} + +func (b *platformBootclasspathModule) getImageConfig(ctx android.EarlyModuleContext) *bootImageConfig { + return defaultBootImageConfig(ctx) +} + +// generateHiddenAPIBuildActions generates all the hidden API related build rules. +func (b *platformBootclasspathModule) generateHiddenAPIBuildActions(ctx android.ModuleContext, modules []android.Module, fragments []android.Module) bootDexJarByModule { + + // Save the paths to the monolithic files for retrieval via OutputFiles(). + b.hiddenAPIFlagsCSV = hiddenAPISingletonPaths(ctx).flags + b.hiddenAPIIndexCSV = hiddenAPISingletonPaths(ctx).index + b.hiddenAPIMetadataCSV = hiddenAPISingletonPaths(ctx).metadata + + bootDexJarByModule := extractBootDexJarsFromModules(ctx, modules) + + // Don't run any hiddenapi rules if UNSAFE_DISABLE_HIDDENAPI_FLAGS=true. This is a performance + // optimization that can be used to reduce the incremental build time but as its name suggests it + // can be unsafe to use, e.g. when the changes affect anything that goes on the bootclasspath. + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + paths := android.OutputPaths{b.hiddenAPIFlagsCSV, b.hiddenAPIIndexCSV, b.hiddenAPIMetadataCSV} + for _, path := range paths { + ctx.Build(pctx, android.BuildParams{ + Rule: android.Touch, + Output: path, + }) + } + return bootDexJarByModule + } + + // Construct a list of ClasspathElement objects from the modules and fragments. + classpathElements := CreateClasspathElements(ctx, modules, fragments) + + monolithicInfo := b.createAndProvideMonolithicHiddenAPIInfo(ctx, classpathElements) + + // Extract the classes jars only from those libraries that do not have corresponding fragments as + // the fragments will have already provided the flags that are needed. + classesJars := monolithicInfo.ClassesJars + + // Create the input to pass to buildRuleToGenerateHiddenAPIStubFlagsFile + input := newHiddenAPIFlagInput() + + // Gather stub library information from the dependencies on modules provided by + // hiddenAPIComputeMonolithicStubLibModules. + input.gatherStubLibInfo(ctx, nil) + + // Use the flag files from this module and all the fragments. + input.FlagFilesByCategory = monolithicInfo.FlagsFilesByCategory + + // Generate the monolithic stub-flags.csv file. + stubFlags := hiddenAPISingletonPaths(ctx).stubFlags + buildRuleToGenerateHiddenAPIStubFlagsFile(ctx, "platform-bootclasspath-monolithic-hiddenapi-stub-flags", "monolithic hidden API stub flags", stubFlags, bootDexJarByModule.bootDexJars(), input, monolithicInfo.StubFlagsPaths) + + // Generate the annotation-flags.csv file from all the module annotations. + annotationFlags := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "annotation-flags-from-classes.csv") + buildRuleToGenerateAnnotationFlags(ctx, "intermediate hidden API flags", classesJars, stubFlags, annotationFlags) + + // Generate the monolithic hiddenapi-flags.csv file. + // + // Use annotation flags generated directly from the classes jars as well as annotation flag files + // provided by prebuilts. + allAnnotationFlagFiles := android.Paths{annotationFlags} + allAnnotationFlagFiles = append(allAnnotationFlagFiles, monolithicInfo.AnnotationFlagsPaths...) + allFlags := hiddenAPISingletonPaths(ctx).flags + buildRuleToGenerateHiddenApiFlags(ctx, "hiddenAPIFlagsFile", "monolithic hidden API flags", allFlags, stubFlags, allAnnotationFlagFiles, monolithicInfo.FlagsFilesByCategory, monolithicInfo.AllFlagsPaths, android.OptionalPath{}) + + // Generate an intermediate monolithic hiddenapi-metadata.csv file directly from the annotations + // in the source code. + intermediateMetadataCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "metadata-from-classes.csv") + buildRuleToGenerateMetadata(ctx, "intermediate hidden API metadata", classesJars, stubFlags, intermediateMetadataCSV) + + // Generate the monolithic hiddenapi-metadata.csv file. + // + // Use metadata files generated directly from the classes jars as well as metadata files provided + // by prebuilts. + // + // This has the side effect of ensuring that the output file uses | quotes just in case that is + // important for the tools that consume the metadata file. + allMetadataFlagFiles := android.Paths{intermediateMetadataCSV} + allMetadataFlagFiles = append(allMetadataFlagFiles, monolithicInfo.MetadataPaths...) + metadataCSV := hiddenAPISingletonPaths(ctx).metadata + b.buildRuleMergeCSV(ctx, "monolithic hidden API metadata", allMetadataFlagFiles, metadataCSV) + + // Generate an intermediate monolithic hiddenapi-index.csv file directly from the CSV files in the + // classes jars. + intermediateIndexCSV := android.PathForModuleOut(ctx, "hiddenapi-monolithic", "index-from-classes.csv") + buildRuleToGenerateIndex(ctx, "intermediate hidden API index", classesJars, intermediateIndexCSV) + + // Generate the monolithic hiddenapi-index.csv file. + // + // Use index files generated directly from the classes jars as well as index files provided + // by prebuilts. + allIndexFlagFiles := android.Paths{intermediateIndexCSV} + allIndexFlagFiles = append(allIndexFlagFiles, monolithicInfo.IndexPaths...) + indexCSV := hiddenAPISingletonPaths(ctx).index + b.buildRuleMergeCSV(ctx, "monolithic hidden API index", allIndexFlagFiles, indexCSV) + + return bootDexJarByModule +} + +// createAndProvideMonolithicHiddenAPIInfo creates a MonolithicHiddenAPIInfo and provides it for +// testing. +func (b *platformBootclasspathModule) createAndProvideMonolithicHiddenAPIInfo(ctx android.ModuleContext, classpathElements ClasspathElements) MonolithicHiddenAPIInfo { + // Create a temporary input structure in which to collate information provided directly by this + // module, either through properties or direct dependencies. + temporaryInput := newHiddenAPIFlagInput() + + // Create paths to the flag files specified in the properties. + temporaryInput.extractFlagFilesFromProperties(ctx, &b.properties.Hidden_api) + + // Create the monolithic info, by starting with the flag files specified on this and then merging + // in information from all the fragment dependencies of this. + monolithicInfo := newMonolithicHiddenAPIInfo(ctx, temporaryInput.FlagFilesByCategory, classpathElements) + + // Store the information for testing. + ctx.SetProvider(MonolithicHiddenAPIInfoProvider, monolithicInfo) + return monolithicInfo +} + +func (b *platformBootclasspathModule) buildRuleMergeCSV(ctx android.ModuleContext, desc string, inputPaths android.Paths, outputPath android.WritablePath) { + rule := android.NewRuleBuilder(pctx, ctx) + rule.Command(). + BuiltTool("merge_csv"). + Flag("--key_field signature"). + FlagWithOutput("--output=", outputPath). + Inputs(inputPaths) + + rule.Build(desc, desc) +} + +// generateHiddenApiMakeVars generates make variables needed by hidden API related make rules, e.g. +// veridex and run-appcompat. +func (b *platformBootclasspathModule) generateHiddenApiMakeVars(ctx android.MakeVarsContext) { + if ctx.Config().IsEnvTrue("UNSAFE_DISABLE_HIDDENAPI_FLAGS") { + return + } + // INTERNAL_PLATFORM_HIDDENAPI_FLAGS is used by Make rules in art/ and cts/. + ctx.Strict("INTERNAL_PLATFORM_HIDDENAPI_FLAGS", b.hiddenAPIFlagsCSV.String()) +} + +// generateBootImageBuildActions generates ninja rules related to the boot image creation. +func (b *platformBootclasspathModule) generateBootImageBuildActions(ctx android.ModuleContext, nonUpdatableModules, updatableModules []android.Module) { + // Force the GlobalSoongConfig to be created and cached for use by the dex_bootjars + // GenerateSingletonBuildActions method as it cannot create it for itself. + dexpreopt.GetGlobalSoongConfig(ctx) + + imageConfig := b.getImageConfig(ctx) + if imageConfig == nil { + return + } + + global := dexpreopt.GetGlobalConfig(ctx) + if !shouldBuildBootImages(ctx.Config(), global) { + return + } + + // Generate the framework profile rule + bootFrameworkProfileRule(ctx, imageConfig) + + // Generate the updatable bootclasspath packages rule. + generateUpdatableBcpPackagesRule(ctx, imageConfig, updatableModules) + + // Copy non-updatable module dex jars to their predefined locations. + nonUpdatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, nonUpdatableModules) + copyBootJarsToPredefinedLocations(ctx, nonUpdatableBootDexJarsByModule, imageConfig.dexPathsByModule) + + // Copy updatable module dex jars to their predefined locations. + config := GetUpdatableBootConfig(ctx) + updatableBootDexJarsByModule := extractEncodedDexJarsFromModules(ctx, updatableModules) + copyBootJarsToPredefinedLocations(ctx, updatableBootDexJarsByModule, config.dexPathsByModule) + + // Build a profile for the image config and then use that to build the boot image. + profile := bootImageProfileRule(ctx, imageConfig) + + // Build boot image files for the android variants. + androidBootImageFilesByArch := buildBootImageVariantsForAndroidOs(ctx, imageConfig, profile) + + // Zip the android variant boot image files up. + buildBootImageZipInPredefinedLocation(ctx, imageConfig, androidBootImageFilesByArch) + + // Build boot image files for the host variants. There are use directly by ART host side tests. + buildBootImageVariantsForBuildOs(ctx, imageConfig, profile) + + dumpOatRules(ctx, imageConfig) +} |