da739a30a6
Generating boot image requires a .prof file provided by the ART apex. When building with prebuilts, this comes via the prebuilt_bootclasspath_fragment module, which acts as a shim for prebuilt_apex/apex_set. If we have multiple prebuilt apexes in the tree, this shim becomes 1:many. This CL prepares dex_bootjars to select the right .prof file when multiple prebuilts exist. Implementation details - Update deps mutator of dex_bootjars to create a dep on all_apex_contributions. The latter contains information about which apex is selected in a specific release configuration. dex_bootjars will create a dependency on the selected apex in a postdeps phase mutator. - All apex module types (apex, prebuilt_apex and apex_set) will set a provider that contains info about the location of the .prof file on host - dex_bootjars will access the provider of the selected apex to get the location of the .prof file This CL does not drop the old mechanism to get the .prof file (i.e. by creating a dep on {prebuilt_}bootclasspath_fragment). Once all mainline modules have been flagged using apex_contributions, the old mechanism will be dropped Bug: 308790457 Test: Added a unit test that checks that the right .prof is selected when multiple prebuilts exists Change-Id: I40fdb21416c46bed32f6ff187ce5153711ec2c69
184 lines
6 KiB
Go
184 lines
6 KiB
Go
// Copyright 2023 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 android
|
|
|
|
import (
|
|
"github.com/google/blueprint"
|
|
"github.com/google/blueprint/proptools"
|
|
)
|
|
|
|
func init() {
|
|
RegisterApexContributionsBuildComponents(InitRegistrationContext)
|
|
}
|
|
|
|
func RegisterApexContributionsBuildComponents(ctx RegistrationContext) {
|
|
ctx.RegisterModuleType("apex_contributions", apexContributionsFactory)
|
|
ctx.RegisterSingletonModuleType("all_apex_contributions", allApexContributionsFactory)
|
|
}
|
|
|
|
type apexContributions struct {
|
|
ModuleBase
|
|
properties contributionProps
|
|
}
|
|
|
|
type contributionProps struct {
|
|
// Name of the mainline module
|
|
Api_domain *string
|
|
// A list of module names that should be used when this contribution
|
|
// is selected via product_config
|
|
// The name should be explicit (foo or prebuilt_foo)
|
|
Contents []string
|
|
}
|
|
|
|
func (m *apexContributions) ApiDomain() string {
|
|
return proptools.String(m.properties.Api_domain)
|
|
}
|
|
|
|
func (m *apexContributions) Contents() []string {
|
|
return m.properties.Contents
|
|
}
|
|
|
|
// apex_contributions contains a list of module names (source or
|
|
// prebuilt) belonging to the mainline module
|
|
// An apex can have multiple apex_contributions modules
|
|
// with different combinations of source or prebuilts, but only one can be
|
|
// selected via product_config.
|
|
func apexContributionsFactory() Module {
|
|
module := &apexContributions{}
|
|
module.AddProperties(&module.properties)
|
|
InitAndroidModule(module)
|
|
return module
|
|
}
|
|
|
|
// This module type does not have any build actions.
|
|
// It provides metadata that is used in post-deps mutator phase for source vs
|
|
// prebuilts selection.
|
|
func (m *apexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
}
|
|
|
|
// A container for apex_contributions.
|
|
// Based on product_config, it will create a dependency on the selected
|
|
// apex_contributions per mainline module
|
|
type allApexContributions struct {
|
|
SingletonModuleBase
|
|
}
|
|
|
|
func allApexContributionsFactory() SingletonModule {
|
|
module := &allApexContributions{}
|
|
InitAndroidModule(module)
|
|
return module
|
|
}
|
|
|
|
type apexContributionsDepTag struct {
|
|
blueprint.BaseDependencyTag
|
|
}
|
|
|
|
var (
|
|
acDepTag = apexContributionsDepTag{}
|
|
)
|
|
|
|
// Creates a dep to each selected apex_contributions
|
|
func (a *allApexContributions) DepsMutator(ctx BottomUpMutatorContext) {
|
|
ctx.AddDependency(ctx.Module(), acDepTag, ctx.Config().AllApexContributions()...)
|
|
}
|
|
|
|
// Set PrebuiltSelectionInfoProvider in post deps phase
|
|
func (a *allApexContributions) SetPrebuiltSelectionInfoProvider(ctx BaseModuleContext) {
|
|
addContentsToProvider := func(p *PrebuiltSelectionInfoMap, m *apexContributions) {
|
|
for _, content := range m.Contents() {
|
|
if !ctx.OtherModuleExists(content) && !ctx.Config().AllowMissingDependencies() {
|
|
ctx.ModuleErrorf("%s listed in apex_contributions %s does not exist\n", content, m.Name())
|
|
}
|
|
pi := &PrebuiltSelectionInfo{
|
|
baseModuleName: RemoveOptionalPrebuiltPrefix(content),
|
|
selectedModuleName: content,
|
|
metadataModuleName: m.Name(),
|
|
apiDomain: m.ApiDomain(),
|
|
}
|
|
p.Add(ctx, pi)
|
|
}
|
|
}
|
|
|
|
p := PrebuiltSelectionInfoMap{}
|
|
ctx.VisitDirectDepsWithTag(acDepTag, func(child Module) {
|
|
if m, ok := child.(*apexContributions); ok {
|
|
addContentsToProvider(&p, m)
|
|
} else {
|
|
ctx.ModuleErrorf("%s is not an apex_contributions module\n", child.Name())
|
|
}
|
|
})
|
|
SetProvider(ctx, PrebuiltSelectionInfoProvider, p)
|
|
}
|
|
|
|
// A provider containing metadata about whether source or prebuilt should be used
|
|
// This provider will be used in prebuilt_select mutator to redirect deps
|
|
var PrebuiltSelectionInfoProvider = blueprint.NewMutatorProvider[PrebuiltSelectionInfoMap]("prebuilt_select")
|
|
|
|
// Map of baseModuleName to the selected source or prebuilt
|
|
type PrebuiltSelectionInfoMap map[string]PrebuiltSelectionInfo
|
|
|
|
// Add a new entry to the map with some validations
|
|
func (pm *PrebuiltSelectionInfoMap) Add(ctx BaseModuleContext, p *PrebuiltSelectionInfo) {
|
|
if p == nil {
|
|
return
|
|
}
|
|
// Do not allow dups. If the base module (without the prebuilt_) has been added before, raise an exception.
|
|
if old, exists := (*pm)[p.baseModuleName]; exists {
|
|
ctx.ModuleErrorf("Cannot use Soong module: %s from apex_contributions: %s because it has been added previously as: %s from apex_contributions: %s\n",
|
|
p.selectedModuleName, p.metadataModuleName, old.selectedModuleName, old.metadataModuleName,
|
|
)
|
|
}
|
|
(*pm)[p.baseModuleName] = *p
|
|
}
|
|
|
|
type PrebuiltSelectionInfo struct {
|
|
// e.g. libc
|
|
baseModuleName string
|
|
// e.g. (libc|prebuilt_libc)
|
|
selectedModuleName string
|
|
// Name of the apex_contributions module
|
|
metadataModuleName string
|
|
// e.g. com.android.runtime
|
|
apiDomain string
|
|
}
|
|
|
|
// Returns true if `name` is explicitly requested using one of the selected
|
|
// apex_contributions metadata modules.
|
|
func (p *PrebuiltSelectionInfoMap) IsSelected(baseModuleName, name string) bool {
|
|
if i, exists := (*p)[baseModuleName]; exists {
|
|
return i.selectedModuleName == name
|
|
} else {
|
|
return false
|
|
}
|
|
}
|
|
|
|
// Return the list of soong modules selected for this api domain
|
|
// In the case of apexes, it is the canonical name of the apex on device (/apex/<apex_name>)
|
|
func (p *PrebuiltSelectionInfoMap) GetSelectedModulesForApiDomain(apiDomain string) []string {
|
|
selected := []string{}
|
|
for _, entry := range *p {
|
|
if entry.apiDomain == apiDomain {
|
|
selected = append(selected, entry.selectedModuleName)
|
|
}
|
|
}
|
|
return selected
|
|
}
|
|
|
|
// This module type does not have any build actions.
|
|
func (a *allApexContributions) GenerateAndroidBuildActions(ctx ModuleContext) {
|
|
}
|
|
|
|
func (a *allApexContributions) GenerateSingletonBuildActions(ctx SingletonContext) {
|
|
}
|