Merge changes I8a99e3d2,I717d7f5e

* changes:
  Remove unused bp2build logic from arch.go
  Split up config.go
This commit is contained in:
Liz Kammer
2022-08-12 20:39:59 +00:00
committed by Gerrit Code Review
6 changed files with 469 additions and 489 deletions

View File

@@ -38,7 +38,9 @@ bootstrap_go_package {
"bazel_paths.go",
"buildinfo_prop.go",
"config.go",
"test_config.go",
"config_bp2build.go",
"configured_jars.go",
"csuite_config.go",
"deapexer.go",
"defaults.go",

View File

@@ -393,54 +393,6 @@ func (target Target) Variations() []blueprint.Variation {
}
}
func registerBp2buildArchPathDepsMutator(ctx RegisterMutatorsContext) {
ctx.BottomUp("bp2build-arch-pathdeps", bp2buildArchPathDepsMutator).Parallel()
}
// add dependencies for architecture specific properties tagged with `android:"path"`
func bp2buildArchPathDepsMutator(ctx BottomUpMutatorContext) {
var module Module
module = ctx.Module()
m := module.base()
if !m.ArchSpecific() {
return
}
// addPathDepsForProps does not descend into sub structs, so we need to descend into the
// arch-specific properties ourselves
var properties []interface{}
for _, archProperties := range m.archProperties {
for _, archProps := range archProperties {
archPropValues := reflect.ValueOf(archProps).Elem()
// there are three "arch" variations, descend into each
for _, variant := range []string{"Arch", "Multilib", "Target"} {
// The properties are an interface, get the value (a pointer) that it points to
archProps := archPropValues.FieldByName(variant).Elem()
if archProps.IsNil() {
continue
}
// And then a pointer to a struct
archProps = archProps.Elem()
for i := 0; i < archProps.NumField(); i += 1 {
f := archProps.Field(i)
// If the value of the field is a struct (as opposed to a pointer to a struct) then step
// into the BlueprintEmbed field.
if f.Kind() == reflect.Struct {
f = f.FieldByName("BlueprintEmbed")
}
if f.IsZero() {
continue
}
props := f.Interface().(interface{})
properties = append(properties, props)
}
}
}
}
addPathDepsForProps(ctx, properties)
}
// osMutator splits an arch-specific module into a variant for each OS that is enabled for the
// module. It uses the HostOrDevice value passed to InitAndroidArchModule and the
// device_supported and host_supported properties to determine which OsTypes are enabled for this
@@ -998,19 +950,13 @@ func filterArchStruct(field reflect.StructField, prefix string) (bool, reflect.S
if string(field.Tag) != `android:"`+strings.Join(values, ",")+`"` {
panic(fmt.Errorf("unexpected tag format %q", field.Tag))
}
// don't delete path tag as it is needed for bp2build
// these tags don't need to be present in the runtime generated struct type.
values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend"})
if len(values) > 0 && values[0] != "path" {
values = RemoveListFromList(values, []string{"arch_variant", "variant_prepend", "path"})
if len(values) > 0 {
panic(fmt.Errorf("unknown tags %q in field %q", values, prefix+field.Name))
} else if len(values) == 1 {
// FIXME(b/200678898): This assumes that the only tag type when there's
// `android:"arch_variant"` is `android` itself and thus clobbers others
field.Tag = reflect.StructTag(`android:"` + strings.Join(values, ",") + `"`)
} else {
field.Tag = ``
}
field.Tag = ``
return true, field
}
return false, field

View File

@@ -66,9 +66,9 @@ func TestFilterArchStruct(t *testing.T) {
}{},
out: &struct {
A *string
B *string `android:"path"`
C *string `android:"path"`
D *string `android:"path"`
B *string
C *string
D *string
}{},
filtered: true,
},

View File

@@ -20,7 +20,6 @@ package android
import (
"bytes"
"encoding/json"
"errors"
"fmt"
"io/ioutil"
"os"
@@ -345,123 +344,6 @@ func NullConfig(outDir, soongOutDir string) Config {
}
}
// TestConfig returns a Config object for testing.
func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
envCopy := make(map[string]string)
for k, v := range env {
envCopy[k] = v
}
// Copy the real PATH value to the test environment, it's needed by
// NonHermeticHostSystemTool() used in x86_darwin_host.go
envCopy["PATH"] = os.Getenv("PATH")
config := &config{
productVariables: productVariables{
DeviceName: stringPtr("test_device"),
DeviceProduct: stringPtr("test_product"),
Platform_sdk_version: intPtr(30),
Platform_sdk_codename: stringPtr("S"),
Platform_base_sdk_extension_version: intPtr(1),
Platform_version_active_codenames: []string{"S", "Tiramisu"},
DeviceSystemSdkVersions: []string{"14", "15"},
Platform_systemsdk_versions: []string{"29", "30"},
AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
AAPTCharacteristics: stringPtr("nosdcard"),
AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
UncompressPrivAppDex: boolPtr(true),
ShippingApiLevel: stringPtr("30"),
},
outDir: buildDir,
soongOutDir: filepath.Join(buildDir, "soong"),
captureBuild: true,
env: envCopy,
// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
// passed to PathForSource or PathForModuleSrc.
TestAllowNonExistentPaths: true,
BazelContext: noopBazelContext{},
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
}
config.deviceConfig = &deviceConfig{
config: config,
}
config.TestProductVariables = &config.productVariables
config.mockFileSystem(bp, fs)
determineBuildOS(config)
return Config{config}
}
func modifyTestConfigToSupportArchMutator(testConfig Config) {
config := testConfig.config
config.Targets = map[OsType][]Target{
Android: []Target{
{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
},
config.BuildOS: []Target{
{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
},
}
if runtime.GOOS == "darwin" {
config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
}
config.BuildOSTarget = config.Targets[config.BuildOS][0]
config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
}
func modifyTestConfigForMusl(config Config) {
delete(config.Targets, config.BuildOS)
config.productVariables.HostMusl = boolPtr(true)
determineBuildOS(config.config)
config.Targets[config.BuildOS] = []Target{
{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
}
config.BuildOSTarget = config.Targets[config.BuildOS][0]
config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
}
// TestArchConfig returns a Config object suitable for using for tests that
// need to run the arch mutator.
func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
testConfig := TestConfig(buildDir, env, bp, fs)
modifyTestConfigToSupportArchMutator(testConfig)
return testConfig
}
// ConfigForAdditionalRun is a config object which is "reset" for another
// bootstrap run. Only per-run data is reset. Data which needs to persist across
// multiple runs in the same program execution is carried over (such as Bazel
// context or environment deps).
func ConfigForAdditionalRun(c Config) (Config, error) {
newConfig, err := NewConfig(c.moduleListFile, c.runGoTests, c.outDir, c.soongOutDir, c.env)
if err != nil {
return Config{}, err
}
newConfig.BazelContext = c.BazelContext
newConfig.envDeps = c.envDeps
return newConfig, nil
}
// NewConfig creates a new Config object. The srcDir argument specifies the path
// to the root source directory. It also loads the config file, if found.
func NewConfig(moduleListFile string, runGoTests bool, outDir, soongOutDir string, availableEnv map[string]string) (Config, error) {
@@ -744,7 +626,8 @@ func (c *config) DeviceName() string {
// these per device type.
//
// NOTE: Do not base conditional logic on this value. It may break product
// inheritance.
//
// inheritance.
func (c *config) DeviceProduct() string {
return *c.productVariables.DeviceProduct
}
@@ -1737,316 +1620,6 @@ func (c *config) IgnorePrefer32OnDevice() bool {
return c.productVariables.IgnorePrefer32OnDevice
}
// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
// Such lists are used in the build system for things like bootclasspath jars or system server jars.
// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
// module name. The pairs come from Make product variables as a list of colon-separated strings.
//
// Examples:
// - "com.android.art:core-oj"
// - "platform:framework"
// - "system_ext:foo"
//
type ConfiguredJarList struct {
// A list of apex components, which can be an apex name,
// or special names like "platform" or "system_ext".
apexes []string
// A list of jar module name components.
jars []string
}
// Len returns the length of the list of jars.
func (l *ConfiguredJarList) Len() int {
return len(l.jars)
}
// Jar returns the idx-th jar component of (apex, jar) pairs.
func (l *ConfiguredJarList) Jar(idx int) string {
return l.jars[idx]
}
// Apex returns the idx-th apex component of (apex, jar) pairs.
func (l *ConfiguredJarList) Apex(idx int) string {
return l.apexes[idx]
}
// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
// given jar module name.
func (l *ConfiguredJarList) ContainsJar(jar string) bool {
return InList(jar, l.jars)
}
// If the list contains the given (apex, jar) pair.
func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
for i := 0; i < l.Len(); i++ {
if apex == l.apexes[i] && jar == l.jars[i] {
return true
}
}
return false
}
// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
// an empty string if not found.
func (l *ConfiguredJarList) ApexOfJar(jar string) string {
if idx := IndexList(jar, l.jars); idx != -1 {
return l.Apex(IndexList(jar, l.jars))
}
return ""
}
// IndexOfJar returns the first pair with the given jar name on the list, or -1
// if not found.
func (l *ConfiguredJarList) IndexOfJar(jar string) int {
return IndexList(jar, l.jars)
}
func copyAndAppend(list []string, item string) []string {
// Create the result list to be 1 longer than the input.
result := make([]string, len(list)+1)
// Copy the whole input list into the result.
count := copy(result, list)
// Insert the extra item at the end.
result[count] = item
return result
}
// Append an (apex, jar) pair to the list.
func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
// Create a copy of the backing arrays before appending to avoid sharing backing
// arrays that are mutated across instances.
apexes := copyAndAppend(l.apexes, apex)
jars := copyAndAppend(l.jars, jar)
return ConfiguredJarList{apexes, jars}
}
// Append a list of (apex, jar) pairs to the list.
func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len()+other.Len())
jars := make([]string, 0, l.Len()+other.Len())
apexes = append(apexes, l.apexes...)
jars = append(jars, l.jars...)
apexes = append(apexes, other.apexes...)
jars = append(jars, other.jars...)
return ConfiguredJarList{apexes, jars}
}
// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len())
jars := make([]string, 0, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
if !list.containsApexJarPair(apex, jar) {
apexes = append(apexes, apex)
jars = append(jars, jar)
}
}
return ConfiguredJarList{apexes, jars}
}
// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
// and any remaining jars that are not on this list.
func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
var apexes []string
var jars []string
for i, jar := range l.jars {
if InList(jar, jarsToKeep) {
apexes = append(apexes, l.apexes[i])
jars = append(jars, jar)
}
}
return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
}
// CopyOfJars returns a copy of the list of strings containing jar module name
// components.
func (l *ConfiguredJarList) CopyOfJars() []string {
return CopyOf(l.jars)
}
// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
// (apex, jar) pairs.
func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
pairs := make([]string, 0, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
pairs = append(pairs, apex+":"+jar)
}
return pairs
}
// BuildPaths returns a list of build paths based on the given directory prefix.
func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
paths := make(WritablePaths, l.Len())
for i, jar := range l.jars {
paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
}
return paths
}
// BuildPathsByModule returns a map from module name to build paths based on the given directory
// prefix.
func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
paths := map[string]WritablePath{}
for _, jar := range l.jars {
paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
}
return paths
}
// UnmarshalJSON converts JSON configuration from raw bytes into a
// ConfiguredJarList structure.
func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
// Try and unmarshal into a []string each item of which contains a pair
// <apex>:<jar>.
var list []string
err := json.Unmarshal(b, &list)
if err != nil {
// Did not work so return
return err
}
apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
if err != nil {
return err
}
l.apexes = apexes
l.jars = jars
return nil
}
func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
if len(l.apexes) != len(l.jars) {
return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
}
list := make([]string, 0, len(l.apexes))
for i := 0; i < len(l.apexes); i++ {
list = append(list, l.apexes[i]+":"+l.jars[i])
}
return json.Marshal(list)
}
// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
//
// TODO(b/139391334): hard coded until we find a good way to query the stem of a
// module before any other mutators are run.
func ModuleStem(module string) string {
if module == "framework-minus-apex" {
return "framework"
}
return module
}
// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
// based on the operating system.
func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
paths := make([]string, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
name := ModuleStem(jar) + ".jar"
var subdir string
if apex == "platform" {
subdir = "system/framework"
} else if apex == "system_ext" {
subdir = "system_ext/framework"
} else {
subdir = filepath.Join("apex", apex, "javalib")
}
if ostype.Class == Host {
paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
} else {
paths[i] = filepath.Join("/", subdir, name)
}
}
return paths
}
func (l *ConfiguredJarList) String() string {
var pairs []string
for i := 0; i < l.Len(); i++ {
pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
}
return strings.Join(pairs, ",")
}
func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
// Now we need to populate this list by splitting each item in the slice of
// pairs and appending them to the appropriate list of apexes or jars.
apexes := make([]string, len(list))
jars := make([]string, len(list))
for i, apexjar := range list {
apex, jar, err := splitConfiguredJarPair(apexjar)
if err != nil {
return nil, nil, err
}
apexes[i] = apex
jars[i] = jar
}
return apexes, jars, nil
}
// Expected format for apexJarValue = <apex name>:<jar name>
func splitConfiguredJarPair(str string) (string, string, error) {
pair := strings.SplitN(str, ":", 2)
if len(pair) == 2 {
apex := pair[0]
jar := pair[1]
if apex == "" {
return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
}
return apex, jar, nil
} else {
return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
}
}
// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
b, err := json.Marshal(list)
if err != nil {
panic(err)
}
var jarList ConfiguredJarList
err = json.Unmarshal(b, &jarList)
if err != nil {
panic(err)
}
return jarList
}
// EmptyConfiguredJarList returns an empty jar list.
func EmptyConfiguredJarList() ConfiguredJarList {
return ConfiguredJarList{}
}
var earlyBootJarsKey = NewOnceKey("earlyBootJars")
func (c *config) BootJars() []string {
return c.Once(earlyBootJarsKey, func() interface{} {
list := c.productVariables.BootJars.CopyOfJars()

314
android/configured_jars.go Normal file
View File

@@ -0,0 +1,314 @@
// Copyright 2022 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 (
"encoding/json"
"errors"
"fmt"
"path/filepath"
"strings"
)
// The ConfiguredJarList struct provides methods for handling a list of (apex, jar) pairs.
// Such lists are used in the build system for things like bootclasspath jars or system server jars.
// The apex part is either an apex name, or a special names "platform" or "system_ext". Jar is a
// module name. The pairs come from Make product variables as a list of colon-separated strings.
//
// Examples:
// - "com.android.art:core-oj"
// - "platform:framework"
// - "system_ext:foo"
type ConfiguredJarList struct {
// A list of apex components, which can be an apex name,
// or special names like "platform" or "system_ext".
apexes []string
// A list of jar module name components.
jars []string
}
// Len returns the length of the list of jars.
func (l *ConfiguredJarList) Len() int {
return len(l.jars)
}
// Jar returns the idx-th jar component of (apex, jar) pairs.
func (l *ConfiguredJarList) Jar(idx int) string {
return l.jars[idx]
}
// Apex returns the idx-th apex component of (apex, jar) pairs.
func (l *ConfiguredJarList) Apex(idx int) string {
return l.apexes[idx]
}
// ContainsJar returns true if the (apex, jar) pairs contains a pair with the
// given jar module name.
func (l *ConfiguredJarList) ContainsJar(jar string) bool {
return InList(jar, l.jars)
}
// If the list contains the given (apex, jar) pair.
func (l *ConfiguredJarList) containsApexJarPair(apex, jar string) bool {
for i := 0; i < l.Len(); i++ {
if apex == l.apexes[i] && jar == l.jars[i] {
return true
}
}
return false
}
// ApexOfJar returns the apex component of the first pair with the given jar name on the list, or
// an empty string if not found.
func (l *ConfiguredJarList) ApexOfJar(jar string) string {
if idx := IndexList(jar, l.jars); idx != -1 {
return l.Apex(IndexList(jar, l.jars))
}
return ""
}
// IndexOfJar returns the first pair with the given jar name on the list, or -1
// if not found.
func (l *ConfiguredJarList) IndexOfJar(jar string) int {
return IndexList(jar, l.jars)
}
func copyAndAppend(list []string, item string) []string {
// Create the result list to be 1 longer than the input.
result := make([]string, len(list)+1)
// Copy the whole input list into the result.
count := copy(result, list)
// Insert the extra item at the end.
result[count] = item
return result
}
// Append an (apex, jar) pair to the list.
func (l *ConfiguredJarList) Append(apex string, jar string) ConfiguredJarList {
// Create a copy of the backing arrays before appending to avoid sharing backing
// arrays that are mutated across instances.
apexes := copyAndAppend(l.apexes, apex)
jars := copyAndAppend(l.jars, jar)
return ConfiguredJarList{apexes, jars}
}
// Append a list of (apex, jar) pairs to the list.
func (l *ConfiguredJarList) AppendList(other *ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len()+other.Len())
jars := make([]string, 0, l.Len()+other.Len())
apexes = append(apexes, l.apexes...)
jars = append(jars, l.jars...)
apexes = append(apexes, other.apexes...)
jars = append(jars, other.jars...)
return ConfiguredJarList{apexes, jars}
}
// RemoveList filters out a list of (apex, jar) pairs from the receiving list of pairs.
func (l *ConfiguredJarList) RemoveList(list ConfiguredJarList) ConfiguredJarList {
apexes := make([]string, 0, l.Len())
jars := make([]string, 0, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
if !list.containsApexJarPair(apex, jar) {
apexes = append(apexes, apex)
jars = append(jars, jar)
}
}
return ConfiguredJarList{apexes, jars}
}
// Filter keeps the entries if a jar appears in the given list of jars to keep. Returns a new list
// and any remaining jars that are not on this list.
func (l *ConfiguredJarList) Filter(jarsToKeep []string) (ConfiguredJarList, []string) {
var apexes []string
var jars []string
for i, jar := range l.jars {
if InList(jar, jarsToKeep) {
apexes = append(apexes, l.apexes[i])
jars = append(jars, jar)
}
}
return ConfiguredJarList{apexes, jars}, RemoveListFromList(jarsToKeep, jars)
}
// CopyOfJars returns a copy of the list of strings containing jar module name
// components.
func (l *ConfiguredJarList) CopyOfJars() []string {
return CopyOf(l.jars)
}
// CopyOfApexJarPairs returns a copy of the list of strings with colon-separated
// (apex, jar) pairs.
func (l *ConfiguredJarList) CopyOfApexJarPairs() []string {
pairs := make([]string, 0, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
pairs = append(pairs, apex+":"+jar)
}
return pairs
}
// BuildPaths returns a list of build paths based on the given directory prefix.
func (l *ConfiguredJarList) BuildPaths(ctx PathContext, dir OutputPath) WritablePaths {
paths := make(WritablePaths, l.Len())
for i, jar := range l.jars {
paths[i] = dir.Join(ctx, ModuleStem(jar)+".jar")
}
return paths
}
// BuildPathsByModule returns a map from module name to build paths based on the given directory
// prefix.
func (l *ConfiguredJarList) BuildPathsByModule(ctx PathContext, dir OutputPath) map[string]WritablePath {
paths := map[string]WritablePath{}
for _, jar := range l.jars {
paths[jar] = dir.Join(ctx, ModuleStem(jar)+".jar")
}
return paths
}
// UnmarshalJSON converts JSON configuration from raw bytes into a
// ConfiguredJarList structure.
func (l *ConfiguredJarList) UnmarshalJSON(b []byte) error {
// Try and unmarshal into a []string each item of which contains a pair
// <apex>:<jar>.
var list []string
err := json.Unmarshal(b, &list)
if err != nil {
// Did not work so return
return err
}
apexes, jars, err := splitListOfPairsIntoPairOfLists(list)
if err != nil {
return err
}
l.apexes = apexes
l.jars = jars
return nil
}
func (l *ConfiguredJarList) MarshalJSON() ([]byte, error) {
if len(l.apexes) != len(l.jars) {
return nil, errors.New(fmt.Sprintf("Inconsistent ConfiguredJarList: apexes: %q, jars: %q", l.apexes, l.jars))
}
list := make([]string, 0, len(l.apexes))
for i := 0; i < len(l.apexes); i++ {
list = append(list, l.apexes[i]+":"+l.jars[i])
}
return json.Marshal(list)
}
// ModuleStem hardcodes the stem of framework-minus-apex to return "framework".
//
// TODO(b/139391334): hard coded until we find a good way to query the stem of a
// module before any other mutators are run.
func ModuleStem(module string) string {
if module == "framework-minus-apex" {
return "framework"
}
return module
}
// DevicePaths computes the on-device paths for the list of (apex, jar) pairs,
// based on the operating system.
func (l *ConfiguredJarList) DevicePaths(cfg Config, ostype OsType) []string {
paths := make([]string, l.Len())
for i, jar := range l.jars {
apex := l.apexes[i]
name := ModuleStem(jar) + ".jar"
var subdir string
if apex == "platform" {
subdir = "system/framework"
} else if apex == "system_ext" {
subdir = "system_ext/framework"
} else {
subdir = filepath.Join("apex", apex, "javalib")
}
if ostype.Class == Host {
paths[i] = filepath.Join(cfg.Getenv("OUT_DIR"), "host", cfg.PrebuiltOS(), subdir, name)
} else {
paths[i] = filepath.Join("/", subdir, name)
}
}
return paths
}
func (l *ConfiguredJarList) String() string {
var pairs []string
for i := 0; i < l.Len(); i++ {
pairs = append(pairs, l.apexes[i]+":"+l.jars[i])
}
return strings.Join(pairs, ",")
}
func splitListOfPairsIntoPairOfLists(list []string) ([]string, []string, error) {
// Now we need to populate this list by splitting each item in the slice of
// pairs and appending them to the appropriate list of apexes or jars.
apexes := make([]string, len(list))
jars := make([]string, len(list))
for i, apexjar := range list {
apex, jar, err := splitConfiguredJarPair(apexjar)
if err != nil {
return nil, nil, err
}
apexes[i] = apex
jars[i] = jar
}
return apexes, jars, nil
}
// Expected format for apexJarValue = <apex name>:<jar name>
func splitConfiguredJarPair(str string) (string, string, error) {
pair := strings.SplitN(str, ":", 2)
if len(pair) == 2 {
apex := pair[0]
jar := pair[1]
if apex == "" {
return apex, jar, fmt.Errorf("invalid apex '%s' in <apex>:<jar> pair '%s', expected format: <apex>:<jar>", apex, str)
}
return apex, jar, nil
} else {
return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: <apex>:<jar>", str)
}
}
// EmptyConfiguredJarList returns an empty jar list.
func EmptyConfiguredJarList() ConfiguredJarList {
return ConfiguredJarList{}
}
var earlyBootJarsKey = NewOnceKey("earlyBootJars")

145
android/test_config.go Normal file
View File

@@ -0,0 +1,145 @@
// Copyright 2022 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 (
"encoding/json"
"os"
"path/filepath"
"runtime"
"github.com/google/blueprint/proptools"
)
// TestConfig returns a Config object for testing.
func TestConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
envCopy := make(map[string]string)
for k, v := range env {
envCopy[k] = v
}
// Copy the real PATH value to the test environment, it's needed by
// NonHermeticHostSystemTool() used in x86_darwin_host.go
envCopy["PATH"] = os.Getenv("PATH")
config := &config{
productVariables: productVariables{
DeviceName: stringPtr("test_device"),
DeviceProduct: stringPtr("test_product"),
Platform_sdk_version: intPtr(30),
Platform_sdk_codename: stringPtr("S"),
Platform_base_sdk_extension_version: intPtr(1),
Platform_version_active_codenames: []string{"S", "Tiramisu"},
DeviceSystemSdkVersions: []string{"14", "15"},
Platform_systemsdk_versions: []string{"29", "30"},
AAPTConfig: []string{"normal", "large", "xlarge", "hdpi", "xhdpi", "xxhdpi"},
AAPTPreferredConfig: stringPtr("xhdpi"),
AAPTCharacteristics: stringPtr("nosdcard"),
AAPTPrebuiltDPI: []string{"xhdpi", "xxhdpi"},
UncompressPrivAppDex: boolPtr(true),
ShippingApiLevel: stringPtr("30"),
},
outDir: buildDir,
soongOutDir: filepath.Join(buildDir, "soong"),
captureBuild: true,
env: envCopy,
// Set testAllowNonExistentPaths so that test contexts don't need to specify every path
// passed to PathForSource or PathForModuleSrc.
TestAllowNonExistentPaths: true,
BazelContext: noopBazelContext{},
mixedBuildDisabledModules: make(map[string]struct{}),
mixedBuildEnabledModules: make(map[string]struct{}),
}
config.deviceConfig = &deviceConfig{
config: config,
}
config.TestProductVariables = &config.productVariables
config.mockFileSystem(bp, fs)
determineBuildOS(config)
return Config{config}
}
func modifyTestConfigToSupportArchMutator(testConfig Config) {
config := testConfig.config
config.Targets = map[OsType][]Target{
Android: []Target{
{Android, Arch{ArchType: Arm64, ArchVariant: "armv8-a", Abi: []string{"arm64-v8a"}}, NativeBridgeDisabled, "", "", false},
{Android, Arch{ArchType: Arm, ArchVariant: "armv7-a-neon", Abi: []string{"armeabi-v7a"}}, NativeBridgeDisabled, "", "", false},
},
config.BuildOS: []Target{
{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
},
}
if runtime.GOOS == "darwin" {
config.Targets[config.BuildOS] = config.Targets[config.BuildOS][:1]
}
config.BuildOSTarget = config.Targets[config.BuildOS][0]
config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
config.AndroidCommonTarget = getCommonTargets(config.Targets[Android])[0]
config.AndroidFirstDeviceTarget = FirstTarget(config.Targets[Android], "lib64", "lib32")[0]
config.TestProductVariables.DeviceArch = proptools.StringPtr("arm64")
config.TestProductVariables.DeviceArchVariant = proptools.StringPtr("armv8-a")
config.TestProductVariables.DeviceSecondaryArch = proptools.StringPtr("arm")
config.TestProductVariables.DeviceSecondaryArchVariant = proptools.StringPtr("armv7-a-neon")
}
func modifyTestConfigForMusl(config Config) {
delete(config.Targets, config.BuildOS)
config.productVariables.HostMusl = boolPtr(true)
determineBuildOS(config.config)
config.Targets[config.BuildOS] = []Target{
{config.BuildOS, Arch{ArchType: X86_64}, NativeBridgeDisabled, "", "", false},
{config.BuildOS, Arch{ArchType: X86}, NativeBridgeDisabled, "", "", false},
}
config.BuildOSTarget = config.Targets[config.BuildOS][0]
config.BuildOSCommonTarget = getCommonTargets(config.Targets[config.BuildOS])[0]
}
// TestArchConfig returns a Config object suitable for using for tests that
// need to run the arch mutator.
func TestArchConfig(buildDir string, env map[string]string, bp string, fs map[string][]byte) Config {
testConfig := TestConfig(buildDir, env, bp, fs)
modifyTestConfigToSupportArchMutator(testConfig)
return testConfig
}
// CreateTestConfiguredJarList is a function to create ConfiguredJarList for tests.
func CreateTestConfiguredJarList(list []string) ConfiguredJarList {
// Create the ConfiguredJarList in as similar way as it is created at runtime by marshalling to
// a json list of strings and then unmarshalling into a ConfiguredJarList instance.
b, err := json.Marshal(list)
if err != nil {
panic(err)
}
var jarList ConfiguredJarList
err = json.Unmarshal(b, &jarList)
if err != nil {
panic(err)
}
return jarList
}