From 7ec40ccb159f38d956b070d570a94b2ab55be7c1 Mon Sep 17 00:00:00 2001 From: Liz Kammer Date: Fri, 29 Jul 2022 10:44:23 -0400 Subject: [PATCH] Split up config.go Test: go test soong tests Change-Id: I717d7f5eec4ce33f71c23ab613a26c33b2b8f203 --- android/Android.bp | 2 + android/config.go | 431 +------------------------------------ android/configured_jars.go | 314 +++++++++++++++++++++++++++ android/test_config.go | 145 +++++++++++++ 4 files changed, 463 insertions(+), 429 deletions(-) create mode 100644 android/configured_jars.go create mode 100644 android/test_config.go diff --git a/android/Android.bp b/android/Android.bp index cbd345945..a8c6525c4 100644 --- a/android/Android.bp +++ b/android/Android.bp @@ -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", diff --git a/android/config.go b/android/config.go index 8c7d789c8..202898b12 100644 --- a/android/config.go +++ b/android/config.go @@ -19,7 +19,6 @@ package android import ( "encoding/json" - "errors" "fmt" "io/ioutil" "os" @@ -341,123 +340,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) { @@ -740,7 +622,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 } @@ -1729,316 +1612,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 - // :. - 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 = : -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 : pair '%s', expected format: :", apex, str) - } - return apex, jar, nil - } else { - return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: :", 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() diff --git a/android/configured_jars.go b/android/configured_jars.go new file mode 100644 index 000000000..53fef052a --- /dev/null +++ b/android/configured_jars.go @@ -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 + // :. + 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 = : +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 : pair '%s', expected format: :", apex, str) + } + return apex, jar, nil + } else { + return "error-apex", "error-jar", fmt.Errorf("malformed (apex, jar) pair: '%s', expected format: :", str) + } +} + +// EmptyConfiguredJarList returns an empty jar list. +func EmptyConfiguredJarList() ConfiguredJarList { + return ConfiguredJarList{} +} + +var earlyBootJarsKey = NewOnceKey("earlyBootJars") diff --git a/android/test_config.go b/android/test_config.go new file mode 100644 index 000000000..f36e8ba6a --- /dev/null +++ b/android/test_config.go @@ -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 +}