Merge "Add test suite to legacy core platform allowlist."
diff --git a/android/Android.bp b/android/Android.bp
index f17a8a0..9f6ae02 100644
--- a/android/Android.bp
+++ b/android/Android.bp
@@ -12,6 +12,7 @@
"soong",
"soong-android-soongconfig",
"soong-bazel",
+ "soong-cquery",
"soong-shared",
"soong-ui-metrics_proto",
],
@@ -67,6 +68,7 @@
"singleton.go",
"singleton_module.go",
"soong_config_modules.go",
+ "test_asserts.go",
"test_suites.go",
"testing.go",
"util.go",
diff --git a/android/apex.go b/android/apex.go
index a014592..79d8cdd 100644
--- a/android/apex.go
+++ b/android/apex.go
@@ -719,6 +719,8 @@
// Generate two module out files:
// 1. FullList with transitive deps and their parents in the dep graph
// 2. FlatList with a flat list of transitive deps
+// In both cases transitive deps of external deps are not included. Neither are deps that are only
+// available to APEXes; they are developed with updatability in mind and don't need manual approval.
func (d *ApexBundleDepsInfo) BuildDepsInfoLists(ctx ModuleContext, minSdkVersion string, depInfos DepNameToDepInfoMap) {
var fullContent strings.Builder
var flatContent strings.Builder
diff --git a/android/bazel.go b/android/bazel.go
index 9939bd5..683495b 100644
--- a/android/bazel.go
+++ b/android/bazel.go
@@ -14,19 +14,49 @@
package android
-import "android/soong/bazel"
+import (
+ "fmt"
+ "io/ioutil"
+ "path/filepath"
+ "strings"
+
+ "github.com/google/blueprint"
+ "github.com/google/blueprint/proptools"
+)
+
+type bazelModuleProperties struct {
+ // The label of the Bazel target replacing this Soong module. When run in conversion mode, this
+ // will import the handcrafted build target into the autogenerated file. Note: this may result in
+ // a conflict due to duplicate targets if bp2build_available is also set.
+ Label *string
+
+ // If true, bp2build will generate the converted Bazel target for this module. Note: this may
+ // cause a conflict due to the duplicate targets if label is also set.
+ Bp2build_available bool
+}
+
+// Properties contains common module properties for Bazel migration purposes.
+type properties struct {
+ // In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
+ // this Soong module.
+ Bazel_module bazelModuleProperties
+}
// BazelModuleBase contains the property structs with metadata for modules which can be converted to
// Bazel.
type BazelModuleBase struct {
- bazelProperties bazel.Properties
+ bazelProperties properties
}
// Bazelable is specifies the interface for modules that can be converted to Bazel.
type Bazelable interface {
- bazelProps() *bazel.Properties
- GetBazelLabel() string
+ bazelProps() *properties
+ HasHandcraftedLabel() bool
+ HandcraftedLabel() string
+ GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string
ConvertWithBp2build() bool
+ GetBazelBuildFileContents(c Config, path, name string) (string, error)
+ ConvertedToBazel() bool
}
// BazelModule is a lightweight wrapper interface around Module for Bazel-convertible modules.
@@ -42,16 +72,60 @@
}
// bazelProps returns the Bazel properties for the given BazelModuleBase.
-func (b *BazelModuleBase) bazelProps() *bazel.Properties {
+func (b *BazelModuleBase) bazelProps() *properties {
return &b.bazelProperties
}
+// HasHandcraftedLabel returns whether this module has a handcrafted Bazel label.
+func (b *BazelModuleBase) HasHandcraftedLabel() bool {
+ return b.bazelProperties.Bazel_module.Label != nil
+}
+
+// HandcraftedLabel returns the handcrafted label for this module, or empty string if there is none
+func (b *BazelModuleBase) HandcraftedLabel() string {
+ return proptools.String(b.bazelProperties.Bazel_module.Label)
+}
+
// GetBazelLabel returns the Bazel label for the given BazelModuleBase.
-func (b *BazelModuleBase) GetBazelLabel() string {
- return b.bazelProperties.Bazel_module.Label
+func (b *BazelModuleBase) GetBazelLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
+ if b.HasHandcraftedLabel() {
+ return b.HandcraftedLabel()
+ }
+ if b.ConvertWithBp2build() {
+ return bp2buildModuleLabel(ctx, module)
+ }
+ return "" // no label for unconverted module
}
// ConvertWithBp2build returns whether the given BazelModuleBase should be converted with bp2build.
func (b *BazelModuleBase) ConvertWithBp2build() bool {
return b.bazelProperties.Bazel_module.Bp2build_available
}
+
+// GetBazelBuildFileContents returns the file contents of a hand-crafted BUILD file if available or
+// an error if there are errors reading the file.
+// TODO(b/181575318): currently we append the whole BUILD file, let's change that to do
+// something more targeted based on the rule type and target.
+func (b *BazelModuleBase) GetBazelBuildFileContents(c Config, path, name string) (string, error) {
+ if !strings.Contains(b.HandcraftedLabel(), path) {
+ return "", fmt.Errorf("%q not found in bazel_module.label %q", path, b.HandcraftedLabel())
+ }
+ name = filepath.Join(path, name)
+ f, err := c.fs.Open(name)
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+
+ data, err := ioutil.ReadAll(f)
+ if err != nil {
+ return "", err
+ }
+ return string(data[:]), nil
+}
+
+// ConvertedToBazel returns whether this module has been converted to Bazel, whether automatically
+// or manually
+func (b *BazelModuleBase) ConvertedToBazel() bool {
+ return b.ConvertWithBp2build() || b.HasHandcraftedLabel()
+}
diff --git a/android/bazel_handler.go b/android/bazel_handler.go
index 6675840..bbec389 100644
--- a/android/bazel_handler.go
+++ b/android/bazel_handler.go
@@ -26,6 +26,7 @@
"strings"
"sync"
+ "android/soong/bazel/cquery"
"github.com/google/blueprint/bootstrap"
"android/soong/bazel"
@@ -43,7 +44,7 @@
// Map key to describe bazel cquery requests.
type cqueryKey struct {
label string
- requestType CqueryRequestType
+ requestType cquery.RequestType
archType ArchType
}
@@ -53,14 +54,15 @@
// has been queued to be run later.
// Returns result files built by building the given bazel target label.
- GetAllFiles(label string, archType ArchType) ([]string, bool)
+ GetOutputFiles(label string, archType ArchType) ([]string, bool)
// Returns object files produced by compiling the given cc-related target.
// Retrieves these files from Bazel's CcInfo provider.
GetCcObjectFiles(label string, archType ArchType) ([]string, bool)
- // Returns the results of GetAllFiles and GetCcObjectFiles in a single query (in that order).
- GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
+ // TODO(cparsons): Other cquery-related methods should be added here.
+ // Returns the results of GetOutputFiles and GetCcObjectFiles in a single query (in that order).
+ GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool)
// ** End cquery methods
@@ -109,7 +111,7 @@
AllFiles map[string][]string
}
-func (m MockBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
+func (m MockBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
result, ok := m.AllFiles[label]
return result, ok
}
@@ -119,7 +121,7 @@
return result, ok
}
-func (m MockBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+func (m MockBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
result, ok := m.AllFiles[label]
return result, result, ok
}
@@ -142,43 +144,42 @@
var _ BazelContext = MockBazelContext{}
-func (bazelCtx *bazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := bazelCtx.cquery(label, getAllFiles, archType)
+func (bazelCtx *bazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
+ rawString, ok := bazelCtx.cquery(label, cquery.GetOutputFiles, archType)
+ var ret []string
if ok {
- bazelOutput := strings.TrimSpace(result)
- return strings.Split(bazelOutput, ", "), true
- } else {
- return nil, false
+ bazelOutput := strings.TrimSpace(rawString)
+ ret = cquery.GetOutputFiles.ParseResult(bazelOutput).([]string)
}
+ return ret, ok
}
func (bazelCtx *bazelContext) GetCcObjectFiles(label string, archType ArchType) ([]string, bool) {
- result, ok := bazelCtx.cquery(label, getCcObjectFiles, archType)
+ rawString, ok := bazelCtx.cquery(label, cquery.GetCcObjectFiles, archType)
+ var returnResult []string
if ok {
- bazelOutput := strings.TrimSpace(result)
- return strings.Split(bazelOutput, ", "), true
- } else {
- return nil, false
+ bazelOutput := strings.TrimSpace(rawString)
+ returnResult = cquery.GetCcObjectFiles.ParseResult(bazelOutput).([]string)
}
+ return returnResult, ok
}
-func (bazelCtx *bazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
- var allFiles []string
+func (bazelCtx *bazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+ var outputFiles []string
var ccObjects []string
- result, ok := bazelCtx.cquery(label, getAllFilesAndCcObjectFiles, archType)
+ result, ok := bazelCtx.cquery(label, cquery.GetOutputFilesAndCcObjectFiles, archType)
if ok {
bazelOutput := strings.TrimSpace(result)
- splitString := strings.Split(bazelOutput, "|")
- allFilesString := splitString[0]
- ccObjectsString := splitString[1]
- allFiles = strings.Split(allFilesString, ", ")
- ccObjects = strings.Split(ccObjectsString, ", ")
+ returnResult := cquery.GetOutputFilesAndCcObjectFiles.ParseResult(bazelOutput).(cquery.GetOutputFilesAndCcObjectFiles_Result)
+ outputFiles = returnResult.OutputFiles
+ ccObjects = returnResult.CcObjectFiles
}
- return allFiles, ccObjects, ok
+
+ return outputFiles, ccObjects, ok
}
-func (n noopBazelContext) GetAllFiles(label string, archType ArchType) ([]string, bool) {
+func (n noopBazelContext) GetOutputFiles(label string, archType ArchType) ([]string, bool) {
panic("unimplemented")
}
@@ -186,7 +187,7 @@
panic("unimplemented")
}
-func (n noopBazelContext) GetAllFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
+func (n noopBazelContext) GetOutputFilesAndCcObjectFiles(label string, archType ArchType) ([]string, []string, bool) {
panic("unimplemented")
}
@@ -260,7 +261,7 @@
// If the given request was already made (and the results are available), then
// returns (result, true). If the request is queued but no results are available,
// then returns ("", false).
-func (context *bazelContext) cquery(label string, requestType CqueryRequestType,
+func (context *bazelContext) cquery(label string, requestType cquery.RequestType,
archType ArchType) (string, bool) {
key := cqueryKey{label, requestType, archType}
if result, ok := context.results[key]; ok {
@@ -485,38 +486,66 @@
strings.Join(deps_arm, ",\n ")))
}
+func indent(original string) string {
+ result := ""
+ for _, line := range strings.Split(original, "\n") {
+ result += " " + line + "\n"
+ }
+ return result
+}
+
// Returns the file contents of the buildroot.cquery file that should be used for the cquery
// expression in order to obtain information about buildroot and its dependencies.
// The contents of this file depend on the bazelContext's requests; requests are enumerated
// and grouped by their request type. The data retrieved for each label depends on its
// request type.
func (context *bazelContext) cqueryStarlarkFileContents() []byte {
+ requestTypeToCqueryIdEntries := map[cquery.RequestType][]string{}
+ for val, _ := range context.requests {
+ cqueryId := getCqueryId(val)
+ mapEntryString := fmt.Sprintf("%q : True", cqueryId)
+ requestTypeToCqueryIdEntries[val.requestType] =
+ append(requestTypeToCqueryIdEntries[val.requestType], mapEntryString)
+ }
+ labelRegistrationMapSection := ""
+ functionDefSection := ""
+ mainSwitchSection := ""
+
+ mapDeclarationFormatString := `
+%s = {
+ %s
+}
+`
+ functionDefFormatString := `
+def %s(target):
+%s
+`
+ mainSwitchSectionFormatString := `
+ if id_string in %s:
+ return id_string + ">>" + %s(target)
+`
+
+ for _, requestType := range cquery.RequestTypes {
+ labelMapName := requestType.Name() + "_Labels"
+ functionName := requestType.Name() + "_Fn"
+ labelRegistrationMapSection += fmt.Sprintf(mapDeclarationFormatString,
+ labelMapName,
+ strings.Join(requestTypeToCqueryIdEntries[requestType], ",\n "))
+ functionDefSection += fmt.Sprintf(functionDefFormatString,
+ functionName,
+ indent(requestType.StarlarkFunctionBody()))
+ mainSwitchSection += fmt.Sprintf(mainSwitchSectionFormatString,
+ labelMapName, functionName)
+ }
+
formatString := `
# This file is generated by soong_build. Do not edit.
-getAllFilesLabels = {
- %s
-}
-getCcObjectFilesLabels = {
- %s
-}
+# Label Map Section
+%s
-getAllFilesAndCcObjectFilesLabels = {
- %s
-}
-
-def get_all_files(target):
- return [f.path for f in target.files.to_list()]
-
-def get_cc_object_files(target):
- result = []
- linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
-
- for linker_input in linker_inputs:
- for library in linker_input.libraries:
- for object in library.objects:
- result += [object.path]
- return result
+# Function Def Section
+%s
def get_arch(target):
buildoptions = build_options(target)
@@ -536,39 +565,16 @@
def format(target):
id_string = str(target.label) + "|" + get_arch(target)
- if id_string in getAllFilesLabels:
- return id_string + ">>" + ', '.join(get_all_files(target))
- elif id_string in getCcObjectFilesLabels:
- return id_string + ">>" + ', '.join(get_cc_object_files(target))
- elif id_string in getAllFilesAndCcObjectFilesLabels:
- return id_string + ">>" + ', '.join(get_all_files(target)) + "|" + ', '.join(get_cc_object_files(target))
- else:
- # This target was not requested via cquery, and thus must be a dependency
- # of a requested target.
- return id_string + ">>NONE"
+
+ # Main switch section
+ %s
+ # This target was not requested via cquery, and thus must be a dependency
+ # of a requested target.
+ return id_string + ">>NONE"
`
- var getAllFilesDeps []string = nil
- var getCcObjectFilesDeps []string = nil
- var getAllFilesAndCcObjectFilesDeps []string = nil
- for val, _ := range context.requests {
- labelWithArch := getCqueryId(val)
- mapEntryString := fmt.Sprintf("%q : True", labelWithArch)
- switch val.requestType {
- case getAllFiles:
- getAllFilesDeps = append(getAllFilesDeps, mapEntryString)
- case getCcObjectFiles:
- getCcObjectFilesDeps = append(getCcObjectFilesDeps, mapEntryString)
- case getAllFilesAndCcObjectFiles:
- getAllFilesAndCcObjectFilesDeps = append(getAllFilesAndCcObjectFilesDeps, mapEntryString)
- }
- }
- getAllFilesDepsString := strings.Join(getAllFilesDeps, ",\n ")
- getCcObjectFilesDepsString := strings.Join(getCcObjectFilesDeps, ",\n ")
- getAllFilesAndCcObjectFilesDepsString := strings.Join(getAllFilesAndCcObjectFilesDeps, ",\n ")
-
- return []byte(fmt.Sprintf(formatString, getAllFilesDepsString, getCcObjectFilesDepsString,
- getAllFilesAndCcObjectFilesDepsString))
+ return []byte(fmt.Sprintf(formatString, labelRegistrationMapSection, functionDefSection,
+ mainSwitchSection))
}
// Returns a workspace-relative path containing build-related metadata required
diff --git a/android/config.go b/android/config.go
index bc1aa3a..614386f 100644
--- a/android/config.go
+++ b/android/config.go
@@ -1411,6 +1411,62 @@
return c.config.productVariables.RecoverySnapshotModules
}
+func createDirsMap(previous map[string]bool, dirs []string) (map[string]bool, error) {
+ var ret = make(map[string]bool)
+ for _, dir := range dirs {
+ clean := filepath.Clean(dir)
+ if previous[clean] || ret[clean] {
+ return nil, fmt.Errorf("Duplicate entry %s", dir)
+ }
+ ret[clean] = true
+ }
+ return ret, nil
+}
+
+func (c *deviceConfig) createDirsMapOnce(onceKey OnceKey, previous map[string]bool, dirs []string) map[string]bool {
+ dirMap := c.Once(onceKey, func() interface{} {
+ ret, err := createDirsMap(previous, dirs)
+ if err != nil {
+ panic(fmt.Errorf("%s: %w", onceKey.key, err))
+ }
+ return ret
+ })
+ if dirMap == nil {
+ return nil
+ }
+ return dirMap.(map[string]bool)
+}
+
+var vendorSnapshotDirsExcludedKey = NewOnceKey("VendorSnapshotDirsExcludedMap")
+
+func (c *deviceConfig) VendorSnapshotDirsExcludedMap() map[string]bool {
+ return c.createDirsMapOnce(vendorSnapshotDirsExcludedKey, nil,
+ c.config.productVariables.VendorSnapshotDirsExcluded)
+}
+
+var vendorSnapshotDirsIncludedKey = NewOnceKey("VendorSnapshotDirsIncludedMap")
+
+func (c *deviceConfig) VendorSnapshotDirsIncludedMap() map[string]bool {
+ excludedMap := c.VendorSnapshotDirsExcludedMap()
+ return c.createDirsMapOnce(vendorSnapshotDirsIncludedKey, excludedMap,
+ c.config.productVariables.VendorSnapshotDirsIncluded)
+}
+
+var recoverySnapshotDirsExcludedKey = NewOnceKey("RecoverySnapshotDirsExcludedMap")
+
+func (c *deviceConfig) RecoverySnapshotDirsExcludedMap() map[string]bool {
+ return c.createDirsMapOnce(recoverySnapshotDirsExcludedKey, nil,
+ c.config.productVariables.RecoverySnapshotDirsExcluded)
+}
+
+var recoverySnapshotDirsIncludedKey = NewOnceKey("RecoverySnapshotDirsIncludedMap")
+
+func (c *deviceConfig) RecoverySnapshotDirsIncludedMap() map[string]bool {
+ excludedMap := c.RecoverySnapshotDirsExcludedMap()
+ return c.createDirsMapOnce(recoverySnapshotDirsIncludedKey, excludedMap,
+ c.config.productVariables.RecoverySnapshotDirsIncluded)
+}
+
func (c *deviceConfig) ShippingApiLevel() ApiLevel {
if c.config.productVariables.ShippingApiLevel == nil {
return NoneApiLevel
diff --git a/android/fixture.go b/android/fixture.go
index 552c8f5..928967d 100644
--- a/android/fixture.go
+++ b/android/fixture.go
@@ -16,8 +16,6 @@
import (
"fmt"
- "reflect"
- "strings"
"testing"
)
@@ -223,7 +221,8 @@
//
// The buildDirSupplier is a pointer to the package level buildDir variable that is initialized by
// the package level setUp method. It has to be a pointer to the variable as the variable will not
-// have been initialized at the time the factory is created.
+// have been initialized at the time the factory is created. If it is nil then a test specific
+// temporary directory will be created instead.
func NewFixtureFactory(buildDirSupplier *string, preparers ...FixturePreparer) FixtureFactory {
return &fixtureFactory{
buildDirSupplier: buildDirSupplier,
@@ -237,8 +236,14 @@
// A set of mock files to add to the mock file system.
type MockFS map[string][]byte
+// Merge adds the extra entries from the supplied map to this one.
+//
+// Fails if the supplied map files with the same paths are present in both of them.
func (fs MockFS) Merge(extra map[string][]byte) {
for p, c := range extra {
+ if _, ok := fs[p]; ok {
+ panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists", p))
+ }
fs[p] = c
}
}
@@ -289,17 +294,40 @@
}
// Add a file to the mock filesystem
+//
+// Fail if the filesystem already contains a file with that path, use FixtureOverrideFile instead.
func FixtureAddFile(path string, contents []byte) FixturePreparer {
return FixtureModifyMockFS(func(fs MockFS) {
+ if _, ok := fs[path]; ok {
+ panic(fmt.Errorf("attempted to add file %s to the mock filesystem but it already exists, use FixtureOverride*File instead", path))
+ }
fs[path] = contents
})
}
// Add a text file to the mock filesystem
+//
+// Fail if the filesystem already contains a file with that path.
func FixtureAddTextFile(path string, contents string) FixturePreparer {
return FixtureAddFile(path, []byte(contents))
}
+// Override a file in the mock filesystem
+//
+// If the file does not exist this behaves as FixtureAddFile.
+func FixtureOverrideFile(path string, contents []byte) FixturePreparer {
+ return FixtureModifyMockFS(func(fs MockFS) {
+ fs[path] = contents
+ })
+}
+
+// Override a text file in the mock filesystem
+//
+// If the file does not exist this behaves as FixtureAddTextFile.
+func FixtureOverrideTextFile(path string, contents string) FixturePreparer {
+ return FixtureOverrideFile(path, []byte(contents))
+}
+
// Add the root Android.bp file with the supplied contents.
func FixtureWithRootAndroidBp(contents string) FixturePreparer {
return FixtureAddTextFile("Android.bp", contents)
@@ -440,16 +468,16 @@
// The supplied result can be used to access the state of the code under test just as the main
// body of the test would but if any errors other than ones expected are reported the state may
// be indeterminate.
- CheckErrors(result *TestResult)
+ CheckErrors(t *testing.T, result *TestResult)
}
type simpleErrorHandler struct {
- function func(result *TestResult)
+ function func(t *testing.T, result *TestResult)
}
-func (h simpleErrorHandler) CheckErrors(result *TestResult) {
- result.Helper()
- h.function(result)
+func (h simpleErrorHandler) CheckErrors(t *testing.T, result *TestResult) {
+ t.Helper()
+ h.function(t, result)
}
// The default fixture error handler.
@@ -459,9 +487,9 @@
// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
// which the test is being run which means that the RunTest() method will not return.
var FixtureExpectsNoErrors = FixtureCustomErrorHandler(
- func(result *TestResult) {
- result.Helper()
- FailIfErrored(result.T, result.Errs)
+ func(t *testing.T, result *TestResult) {
+ t.Helper()
+ FailIfErrored(t, result.Errs)
},
)
@@ -478,10 +506,10 @@
// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
// which the test is being run which means that the RunTest() method will not return.
func FixtureExpectsAtLeastOneErrorMatchingPattern(pattern string) FixtureErrorHandler {
- return FixtureCustomErrorHandler(func(result *TestResult) {
- result.Helper()
- if !FailIfNoMatchingErrors(result.T, pattern, result.Errs) {
- result.FailNow()
+ return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
+ t.Helper()
+ if !FailIfNoMatchingErrors(t, pattern, result.Errs) {
+ t.FailNow()
}
})
}
@@ -500,14 +528,14 @@
// If the test fails this handler will call `result.FailNow()` which will exit the goroutine within
// which the test is being run which means that the RunTest() method will not return.
func FixtureExpectsAllErrorsToMatchAPattern(patterns []string) FixtureErrorHandler {
- return FixtureCustomErrorHandler(func(result *TestResult) {
- result.Helper()
- CheckErrorsAgainstExpectations(result.T, result.Errs, patterns)
+ return FixtureCustomErrorHandler(func(t *testing.T, result *TestResult) {
+ t.Helper()
+ CheckErrorsAgainstExpectations(t, result.Errs, patterns)
})
}
// FixtureCustomErrorHandler creates a custom error handler
-func FixtureCustomErrorHandler(function func(result *TestResult)) FixtureErrorHandler {
+func FixtureCustomErrorHandler(function func(t *testing.T, result *TestResult)) FixtureErrorHandler {
return simpleErrorHandler{
function: function,
}
@@ -519,122 +547,6 @@
RunTest() *TestResult
}
-// Provides general test support.
-type TestHelper struct {
- *testing.T
-}
-
-// AssertBoolEquals checks if the expected and actual values are equal and if they are not then it
-// reports an error prefixed with the supplied message and including a reason for why it failed.
-func (h *TestHelper) AssertBoolEquals(message string, expected bool, actual bool) {
- h.Helper()
- if actual != expected {
- h.Errorf("%s: expected %t, actual %t", message, expected, actual)
- }
-}
-
-// AssertStringEquals checks if the expected and actual values are equal and if they are not then
-// it reports an error prefixed with the supplied message and including a reason for why it failed.
-func (h *TestHelper) AssertStringEquals(message string, expected string, actual string) {
- h.Helper()
- if actual != expected {
- h.Errorf("%s: expected %s, actual %s", message, expected, actual)
- }
-}
-
-// AssertErrorMessageEquals checks if the error is not nil and has the expected message. If it does
-// not then this reports an error prefixed with the supplied message and including a reason for why
-// it failed.
-func (h *TestHelper) AssertErrorMessageEquals(message string, expected string, actual error) {
- h.Helper()
- if actual == nil {
- h.Errorf("Expected error but was nil")
- } else if actual.Error() != expected {
- h.Errorf("%s: expected %s, actual %s", message, expected, actual.Error())
- }
-}
-
-// AssertTrimmedStringEquals checks if the expected and actual values are the same after trimming
-// leading and trailing spaces from them both. If they are not then it reports an error prefixed
-// with the supplied message and including a reason for why it failed.
-func (h *TestHelper) AssertTrimmedStringEquals(message string, expected string, actual string) {
- h.Helper()
- h.AssertStringEquals(message, strings.TrimSpace(expected), strings.TrimSpace(actual))
-}
-
-// AssertStringDoesContain checks if the string contains the expected substring. If it does not
-// then it reports an error prefixed with the supplied message and including a reason for why it
-// failed.
-func (h *TestHelper) AssertStringDoesContain(message string, s string, expectedSubstring string) {
- h.Helper()
- if !strings.Contains(s, expectedSubstring) {
- h.Errorf("%s: could not find %q within %q", message, expectedSubstring, s)
- }
-}
-
-// AssertStringDoesNotContain checks if the string contains the expected substring. If it does then
-// it reports an error prefixed with the supplied message and including a reason for why it failed.
-func (h *TestHelper) AssertStringDoesNotContain(message string, s string, unexpectedSubstring string) {
- h.Helper()
- if strings.Contains(s, unexpectedSubstring) {
- h.Errorf("%s: unexpectedly found %q within %q", message, unexpectedSubstring, s)
- }
-}
-
-// AssertStringListContains checks if the list of strings contains the expected string. If it does
-// not then it reports an error prefixed with the supplied message and including a reason for why it
-// failed.
-func (h *TestHelper) AssertStringListContains(message string, list []string, expected string) {
- h.Helper()
- if !InList(expected, list) {
- h.Errorf("%s: could not find %q within %q", message, expected, list)
- }
-}
-
-// AssertArrayString checks if the expected and actual values are equal and if they are not then it
-// reports an error prefixed with the supplied message and including a reason for why it failed.
-func (h *TestHelper) AssertArrayString(message string, expected, actual []string) {
- h.Helper()
- if len(actual) != len(expected) {
- h.Errorf("%s: expected %d (%q), actual (%d) %q", message, len(expected), expected, len(actual), actual)
- return
- }
- for i := range actual {
- if actual[i] != expected[i] {
- h.Errorf("%s: expected %d-th, %q (%q), actual %q (%q)",
- message, i, expected[i], expected, actual[i], actual)
- return
- }
- }
-}
-
-// AssertDeepEquals checks if the expected and actual values are equal using reflect.DeepEqual and
-// if they are not then it reports an error prefixed with the supplied message and including a
-// reason for why it failed.
-func (h *TestHelper) AssertDeepEquals(message string, expected interface{}, actual interface{}) {
- h.Helper()
- if !reflect.DeepEqual(actual, expected) {
- h.Errorf("%s: expected:\n %#v\n got:\n %#v", message, expected, actual)
- }
-}
-
-// AssertPanic checks that the supplied function panics as expected.
-func (h *TestHelper) AssertPanic(message string, funcThatShouldPanic func()) {
- h.Helper()
- panicked := false
- func() {
- defer func() {
- if x := recover(); x != nil {
- panicked = true
- }
- }()
- funcThatShouldPanic()
- }()
- if !panicked {
- h.Error(message)
- }
-}
-
// Struct to allow TestResult to embed a *TestContext and allow call forwarding to its methods.
type testContext struct {
*TestContext
@@ -642,7 +554,6 @@
// The result of running a test.
type TestResult struct {
- TestHelper
testContext
fixture *fixture
@@ -675,7 +586,16 @@
}
func (f *fixtureFactory) Fixture(t *testing.T, preparers ...FixturePreparer) Fixture {
- config := TestConfig(*f.buildDirSupplier, nil, "", nil)
+ var buildDir string
+ if f.buildDirSupplier == nil {
+ // Create a new temporary directory for this run. It will be automatically cleaned up when the
+ // test finishes.
+ buildDir = t.TempDir()
+ } else {
+ // Retrieve the buildDir from the supplier.
+ buildDir = *f.buildDirSupplier
+ }
+ config := TestConfig(buildDir, nil, "", nil)
ctx := NewTestContext(config)
fixture := &fixture{
factory: f,
@@ -787,14 +707,13 @@
}
result := &TestResult{
- TestHelper: TestHelper{T: f.t},
testContext: testContext{ctx},
fixture: f,
Config: f.config,
Errs: errs,
}
- f.errorHandler.CheckErrors(result)
+ f.errorHandler.CheckErrors(f.t, result)
return result
}
@@ -830,36 +749,7 @@
return result
}
-// NewFixture creates a new test fixture that is based on the one that created this result. It is
-// intended to test the output of module types that generate content to be processed by the build,
-// e.g. sdk snapshots.
-func (r *TestResult) NewFixture(preparers ...FixturePreparer) Fixture {
- return r.fixture.factory.Fixture(r.T, preparers...)
-}
-
-// RunTest is shorthand for NewFixture(preparers...).RunTest().
-func (r *TestResult) RunTest(preparers ...FixturePreparer) *TestResult {
- r.Helper()
- return r.fixture.factory.Fixture(r.T, preparers...).RunTest()
-}
-
// Module returns the module with the specific name and of the specified variant.
func (r *TestResult) Module(name string, variant string) Module {
return r.ModuleForTests(name, variant).Module()
}
-
-// Create a *TestResult object suitable for use within a subtest.
-//
-// This ensures that any errors reported by the TestResult, e.g. from within one of its
-// Assert... methods, will be associated with the sub test and not the main test.
-//
-// result := ....RunTest()
-// t.Run("subtest", func(t *testing.T) {
-// subResult := result.ResultForSubTest(t)
-// subResult.AssertStringEquals("something", ....)
-// })
-func (r *TestResult) ResultForSubTest(t *testing.T) *TestResult {
- subTestResult := *r
- r.T = t
- return &subTestResult
-}
diff --git a/android/fixture_test.go b/android/fixture_test.go
index 5a7bf3b..a31ef16 100644
--- a/android/fixture_test.go
+++ b/android/fixture_test.go
@@ -43,7 +43,6 @@
extension.Fixture(t, preparer1, preparer2, preparer2Then1, preparer3)
- h := TestHelper{t}
- h.AssertDeepEquals("preparers called in wrong order",
+ AssertDeepEquals(t, "preparers called in wrong order",
[]string{"preparer1", "preparer2", "preparer4", "preparer3"}, list)
}
diff --git a/android/licenses_test.go b/android/licenses_test.go
index d0e3533..a581932 100644
--- a/android/licenses_test.go
+++ b/android/licenses_test.go
@@ -482,33 +482,33 @@
RunTest(t)
if test.effectiveLicenses != nil {
- checkEffectiveLicenses(result, test.effectiveLicenses)
+ checkEffectiveLicenses(t, result, test.effectiveLicenses)
}
if test.effectivePackage != nil {
- checkEffectivePackage(result, test.effectivePackage)
+ checkEffectivePackage(t, result, test.effectivePackage)
}
if test.effectiveNotices != nil {
- checkEffectiveNotices(result, test.effectiveNotices)
+ checkEffectiveNotices(t, result, test.effectiveNotices)
}
if test.effectiveKinds != nil {
- checkEffectiveKinds(result, test.effectiveKinds)
+ checkEffectiveKinds(t, result, test.effectiveKinds)
}
if test.effectiveConditions != nil {
- checkEffectiveConditions(result, test.effectiveConditions)
+ checkEffectiveConditions(t, result, test.effectiveConditions)
}
if test.effectiveInheritedLicenses != nil {
- checkEffectiveInheritedLicenses(result, test.effectiveInheritedLicenses)
+ checkEffectiveInheritedLicenses(t, result, test.effectiveInheritedLicenses)
}
})
}
}
-func checkEffectiveLicenses(result *TestResult, effectiveLicenses map[string][]string) {
+func checkEffectiveLicenses(t *testing.T, result *TestResult, effectiveLicenses map[string][]string) {
actualLicenses := make(map[string][]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -522,7 +522,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -538,12 +538,12 @@
licenses = []string{}
}
if !compareUnorderedStringArrays(expectedLicenses, licenses) {
- result.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses)
+ t.Errorf("effective licenses mismatch for module %q: expected %q, found %q", moduleName, expectedLicenses, licenses)
}
}
}
-func checkEffectiveInheritedLicenses(result *TestResult, effectiveInheritedLicenses map[string][]string) {
+func checkEffectiveInheritedLicenses(t *testing.T, result *TestResult, effectiveInheritedLicenses map[string][]string) {
actualLicenses := make(map[string][]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -557,7 +557,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -580,7 +580,7 @@
}
cmodule, ok := c.(Module)
if !ok {
- result.Errorf("%q not a module", c.Name())
+ t.Errorf("%q not a module", c.Name())
return
}
cbase := cmodule.base()
@@ -603,12 +603,12 @@
licenses = []string{}
}
if !compareUnorderedStringArrays(expectedInheritedLicenses, licenses) {
- result.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses)
+ t.Errorf("effective inherited licenses mismatch for module %q: expected %q, found %q", moduleName, expectedInheritedLicenses, licenses)
}
}
}
-func checkEffectivePackage(result *TestResult, effectivePackage map[string]string) {
+func checkEffectivePackage(t *testing.T, result *TestResult, effectivePackage map[string]string) {
actualPackage := make(map[string]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -622,7 +622,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -643,12 +643,12 @@
packageName = ""
}
if expectedPackage != packageName {
- result.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName)
+ t.Errorf("effective package mismatch for module %q: expected %q, found %q", moduleName, expectedPackage, packageName)
}
}
}
-func checkEffectiveNotices(result *TestResult, effectiveNotices map[string][]string) {
+func checkEffectiveNotices(t *testing.T, result *TestResult, effectiveNotices map[string][]string) {
actualNotices := make(map[string][]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -662,7 +662,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -678,12 +678,12 @@
notices = []string{}
}
if !compareUnorderedStringArrays(expectedNotices, notices) {
- result.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices)
+ t.Errorf("effective notice files mismatch for module %q: expected %q, found %q", moduleName, expectedNotices, notices)
}
}
}
-func checkEffectiveKinds(result *TestResult, effectiveKinds map[string][]string) {
+func checkEffectiveKinds(t *testing.T, result *TestResult, effectiveKinds map[string][]string) {
actualKinds := make(map[string][]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -697,7 +697,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -713,12 +713,12 @@
kinds = []string{}
}
if !compareUnorderedStringArrays(expectedKinds, kinds) {
- result.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds)
+ t.Errorf("effective license kinds mismatch for module %q: expected %q, found %q", moduleName, expectedKinds, kinds)
}
}
}
-func checkEffectiveConditions(result *TestResult, effectiveConditions map[string][]string) {
+func checkEffectiveConditions(t *testing.T, result *TestResult, effectiveConditions map[string][]string) {
actualConditions := make(map[string][]string)
result.Context.Context.VisitAllModules(func(m blueprint.Module) {
if _, ok := m.(*licenseModule); ok {
@@ -732,7 +732,7 @@
}
module, ok := m.(Module)
if !ok {
- result.Errorf("%q not a module", m.Name())
+ t.Errorf("%q not a module", m.Name())
return
}
base := module.base()
@@ -748,7 +748,7 @@
conditions = []string{}
}
if !compareUnorderedStringArrays(expectedConditions, conditions) {
- result.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions)
+ t.Errorf("effective license conditions mismatch for module %q: expected %q, found %q", moduleName, expectedConditions, conditions)
}
}
}
diff --git a/android/paths.go b/android/paths.go
index 3f4d3f2..f648c55 100644
--- a/android/paths.go
+++ b/android/paths.go
@@ -339,6 +339,7 @@
EarlyModulePathContext
GetDirectDep(name string) (blueprint.Module, blueprint.DependencyTag)
+ Module() Module
OtherModuleName(m blueprint.Module) string
OtherModuleDir(m blueprint.Module) string
}
@@ -434,15 +435,45 @@
// already be resolved by either deps mutator or path deps mutator.
func getOtherModuleLabel(ctx BazelConversionPathContext, dep, tag string) bazel.Label {
m, _ := ctx.GetDirectDep(dep)
- // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
- otherModuleName := ctx.OtherModuleName(m)
- var label bazel.Label
- if otherDir, dir := ctx.OtherModuleDir(m), ctx.ModuleDir(); otherDir != dir {
- label.Label = fmt.Sprintf("//%s:%s", otherDir, otherModuleName)
- } else {
- label.Label = fmt.Sprintf(":%s", otherModuleName)
+ otherLabel := bazelModuleLabel(ctx, m, tag)
+ label := bazelModuleLabel(ctx, ctx.Module(), "")
+ if samePackage(label, otherLabel) {
+ otherLabel = bazelShortLabel(otherLabel)
}
- return label
+
+ return bazel.Label{
+ Label: otherLabel,
+ }
+}
+
+func bazelModuleLabel(ctx BazelConversionPathContext, module blueprint.Module, tag string) string {
+ // TODO(b/165114590): Convert tag (":name{.tag}") to corresponding Bazel implicit output targets.
+ b, ok := module.(Bazelable)
+ // TODO(b/181155349): perhaps return an error here if the module can't be/isn't being converted
+ if !ok || !b.ConvertedToBazel() {
+ return bp2buildModuleLabel(ctx, module)
+ }
+ return b.GetBazelLabel(ctx, module)
+}
+
+func bazelShortLabel(label string) string {
+ i := strings.Index(label, ":")
+ return label[i:]
+}
+
+func bazelPackage(label string) string {
+ i := strings.Index(label, ":")
+ return label[0:i]
+}
+
+func samePackage(label1, label2 string) bool {
+ return bazelPackage(label1) == bazelPackage(label2)
+}
+
+func bp2buildModuleLabel(ctx BazelConversionPathContext, module blueprint.Module) string {
+ moduleName := ctx.OtherModuleName(module)
+ moduleDir := ctx.OtherModuleDir(module)
+ return fmt.Sprintf("//%s:%s", moduleDir, moduleName)
}
// OutputPaths is a slice of OutputPath objects, with helpers to operate on the collection.
diff --git a/android/paths_test.go b/android/paths_test.go
index 14a4773..3734ed2 100644
--- a/android/paths_test.go
+++ b/android/paths_test.go
@@ -1261,6 +1261,52 @@
}
}
+func TestPathRelativeToTop(t *testing.T) {
+ testConfig := pathTestConfig("/tmp/build/top")
+ deviceTarget := Target{Os: Android, Arch: Arch{ArchType: Arm64}}
+
+ ctx := &testModuleInstallPathContext{
+ baseModuleContext: baseModuleContext{
+ os: deviceTarget.Os,
+ target: deviceTarget,
+ },
+ }
+ ctx.baseModuleContext.config = testConfig
+
+ t.Run("install for soong", func(t *testing.T) {
+ p := PathForModuleInstall(ctx, "install/path")
+ AssertPathRelativeToTopEquals(t, "install path for soong", "out/soong/target/product/test_device/system/install/path", p)
+ })
+ t.Run("install for make", func(t *testing.T) {
+ p := PathForModuleInstall(ctx, "install/path").ToMakePath()
+ AssertPathRelativeToTopEquals(t, "install path for make", "out/target/product/test_device/system/install/path", p)
+ })
+ t.Run("output", func(t *testing.T) {
+ p := PathForOutput(ctx, "output/path")
+ AssertPathRelativeToTopEquals(t, "output path", "out/soong/output/path", p)
+ })
+ t.Run("source", func(t *testing.T) {
+ p := PathForSource(ctx, "source/path")
+ AssertPathRelativeToTopEquals(t, "source path", "source/path", p)
+ })
+ t.Run("mixture", func(t *testing.T) {
+ paths := Paths{
+ PathForModuleInstall(ctx, "install/path"),
+ PathForModuleInstall(ctx, "install/path").ToMakePath(),
+ PathForOutput(ctx, "output/path"),
+ PathForSource(ctx, "source/path"),
+ }
+
+ expected := []string{
+ "out/soong/target/product/test_device/system/install/path",
+ "out/target/product/test_device/system/install/path",
+ "out/soong/output/path",
+ "source/path",
+ }
+ AssertPathsRelativeToTopEquals(t, "mixture", expected, paths)
+ })
+}
+
func ExampleOutputPath_ReplaceExtension() {
ctx := &configErrorWrapper{
config: TestConfig("out", nil, "", nil),
diff --git a/android/test_asserts.go b/android/test_asserts.go
new file mode 100644
index 0000000..5100abb
--- /dev/null
+++ b/android/test_asserts.go
@@ -0,0 +1,162 @@
+// 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 android
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+)
+
+// This file contains general purpose test assert functions.
+
+// AssertBoolEquals checks if the expected and actual values are equal and if they are not then it
+// reports an error prefixed with the supplied message and including a reason for why it failed.
+func AssertBoolEquals(t *testing.T, message string, expected bool, actual bool) {
+ t.Helper()
+ if actual != expected {
+ t.Errorf("%s: expected %t, actual %t", message, expected, actual)
+ }
+}
+
+// AssertStringEquals checks if the expected and actual values are equal and if they are not then
+// it reports an error prefixed with the supplied message and including a reason for why it failed.
+func AssertStringEquals(t *testing.T, message string, expected string, actual string) {
+ t.Helper()
+ if actual != expected {
+ t.Errorf("%s: expected %s, actual %s", message, expected, actual)
+ }
+}
+
+// AssertPathRelativeToTopEquals checks if the expected value is equal to the result of calling
+// PathRelativeToTop on the actual Path.
+func AssertPathRelativeToTopEquals(t *testing.T, message string, expected string, actual Path) {
+ t.Helper()
+ AssertStringEquals(t, message, expected, PathRelativeToTop(actual))
+}
+
+// AssertPathsRelativeToTopEquals checks if the expected value is equal to the result of calling
+// PathsRelativeToTop on the actual Paths.
+func AssertPathsRelativeToTopEquals(t *testing.T, message string, expected []string, actual Paths) {
+ t.Helper()
+ AssertDeepEquals(t, message, expected, PathsRelativeToTop(actual))
+}
+
+// AssertStringPathRelativeToTopEquals checks if the expected value is equal to the result of calling
+// StringPathRelativeToTop on the actual string path.
+func AssertStringPathRelativeToTopEquals(t *testing.T, message string, config Config, expected string, actual string) {
+ t.Helper()
+ AssertStringEquals(t, message, expected, StringPathRelativeToTop(config.buildDir, actual))
+}
+
+// AssertStringPathsRelativeToTopEquals checks if the expected value is equal to the result of
+// calling StringPathsRelativeToTop on the actual string paths.
+func AssertStringPathsRelativeToTopEquals(t *testing.T, message string, config Config, expected []string, actual []string) {
+ t.Helper()
+ AssertDeepEquals(t, message, expected, StringPathsRelativeToTop(config.buildDir, actual))
+}
+
+// AssertErrorMessageEquals checks if the error is not nil and has the expected message. If it does
+// not then this reports an error prefixed with the supplied message and including a reason for why
+// it failed.
+func AssertErrorMessageEquals(t *testing.T, message string, expected string, actual error) {
+ t.Helper()
+ if actual == nil {
+ t.Errorf("Expected error but was nil")
+ } else if actual.Error() != expected {
+ t.Errorf("%s: expected %s, actual %s", message, expected, actual.Error())
+ }
+}
+
+// AssertTrimmedStringEquals checks if the expected and actual values are the same after trimming
+// leading and trailing spaces from them both. If they are not then it reports an error prefixed
+// with the supplied message and including a reason for why it failed.
+func AssertTrimmedStringEquals(t *testing.T, message string, expected string, actual string) {
+ t.Helper()
+ AssertStringEquals(t, message, strings.TrimSpace(expected), strings.TrimSpace(actual))
+}
+
+// AssertStringDoesContain checks if the string contains the expected substring. If it does not
+// then it reports an error prefixed with the supplied message and including a reason for why it
+// failed.
+func AssertStringDoesContain(t *testing.T, message string, s string, expectedSubstring string) {
+ t.Helper()
+ if !strings.Contains(s, expectedSubstring) {
+ t.Errorf("%s: could not find %q within %q", message, expectedSubstring, s)
+ }
+}
+
+// AssertStringDoesNotContain checks if the string contains the expected substring. If it does then
+// it reports an error prefixed with the supplied message and including a reason for why it failed.
+func AssertStringDoesNotContain(t *testing.T, message string, s string, unexpectedSubstring string) {
+ t.Helper()
+ if strings.Contains(s, unexpectedSubstring) {
+ t.Errorf("%s: unexpectedly found %q within %q", message, unexpectedSubstring, s)
+ }
+}
+
+// AssertStringListContains checks if the list of strings contains the expected string. If it does
+// not then it reports an error prefixed with the supplied message and including a reason for why it
+// failed.
+func AssertStringListContains(t *testing.T, message string, list []string, expected string) {
+ t.Helper()
+ if !InList(expected, list) {
+ t.Errorf("%s: could not find %q within %q", message, expected, list)
+ }
+}
+
+// AssertArrayString checks if the expected and actual values are equal and if they are not then it
+// reports an error prefixed with the supplied message and including a reason for why it failed.
+func AssertArrayString(t *testing.T, message string, expected, actual []string) {
+ t.Helper()
+ if len(actual) != len(expected) {
+ t.Errorf("%s: expected %d (%q), actual (%d) %q", message, len(expected), expected, len(actual), actual)
+ return
+ }
+ for i := range actual {
+ if actual[i] != expected[i] {
+ t.Errorf("%s: expected %d-th, %q (%q), actual %q (%q)",
+ message, i, expected[i], expected, actual[i], actual)
+ return
+ }
+ }
+}
+
+// AssertDeepEquals checks if the expected and actual values are equal using reflect.DeepEqual and
+// if they are not then it reports an error prefixed with the supplied message and including a
+// reason for why it failed.
+func AssertDeepEquals(t *testing.T, message string, expected interface{}, actual interface{}) {
+ t.Helper()
+ if !reflect.DeepEqual(actual, expected) {
+ t.Errorf("%s: expected:\n %#v\n got:\n %#v", message, expected, actual)
+ }
+}
+
+// AssertPanic checks that the supplied function panics as expected.
+func AssertPanic(t *testing.T, message string, funcThatShouldPanic func()) {
+ t.Helper()
+ panicked := false
+ func() {
+ defer func() {
+ if x := recover(); x != nil {
+ panicked = true
+ }
+ }()
+ funcThatShouldPanic()
+ }()
+ if !panicked {
+ t.Error(message)
+ }
+}
diff --git a/android/testing.go b/android/testing.go
index dd3d607..af360fa 100644
--- a/android/testing.go
+++ b/android/testing.go
@@ -813,6 +813,9 @@
// that is relative to the root of the source tree.
//
// The build and source paths should be distinguishable based on their contents.
+//
+// deprecated: use PathRelativeToTop instead as it handles make install paths and differentiates
+// between output and source properly.
func NormalizePathForTesting(path Path) string {
if path == nil {
return "<nil path>"
@@ -828,6 +831,11 @@
return p
}
+// NormalizePathsForTesting creates a slice of strings where each string is the result of applying
+// NormalizePathForTesting to the corresponding Path in the input slice.
+//
+// deprecated: use PathsRelativeToTop instead as it handles make install paths and differentiates
+// between output and source properly.
func NormalizePathsForTesting(paths Paths) []string {
var result []string
for _, path := range paths {
@@ -836,3 +844,100 @@
}
return result
}
+
+// PathRelativeToTop returns a string representation of the path relative to a notional top
+// directory.
+//
+// For a WritablePath it applies StringPathRelativeToTop to it, using the buildDir returned from the
+// WritablePath's buildDir() method. For all other paths, i.e. source paths, that are already
+// relative to the top it just returns their string representation.
+func PathRelativeToTop(path Path) string {
+ if path == nil {
+ return "<nil path>"
+ }
+ p := path.String()
+ if w, ok := path.(WritablePath); ok {
+ buildDir := w.buildDir()
+ return StringPathRelativeToTop(buildDir, p)
+ }
+ return p
+}
+
+// PathsRelativeToTop creates a slice of strings where each string is the result of applying
+// PathRelativeToTop to the corresponding Path in the input slice.
+func PathsRelativeToTop(paths Paths) []string {
+ var result []string
+ for _, path := range paths {
+ relative := PathRelativeToTop(path)
+ result = append(result, relative)
+ }
+ return result
+}
+
+// StringPathRelativeToTop returns a string representation of the path relative to a notional top
+// directory.
+//
+// A standard build has the following structure:
+// ../top/
+// out/ - make install files go here.
+// out/soong - this is the buildDir passed to NewTestConfig()
+// ... - the source files
+//
+// This function converts a path so that it appears relative to the ../top/ directory, i.e.
+// * Make install paths, which have the pattern "buildDir/../<path>" are converted into the top
+// relative path "out/<path>"
+// * Soong install paths and other writable paths, which have the pattern "buildDir/<path>" are
+// converted into the top relative path "out/soong/<path>".
+// * Source paths are already relative to the top.
+//
+// This is provided for processing paths that have already been converted into a string, e.g. paths
+// in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against
+// which it can try and relativize paths. PathRelativeToTop must be used for process Path objects.
+func StringPathRelativeToTop(soongOutDir string, path string) string {
+
+ // A relative path must be a source path so leave it as it is.
+ if !filepath.IsAbs(path) {
+ return path
+ }
+
+ // Check to see if the path is relative to the soong out dir.
+ rel, isRel, err := maybeRelErr(soongOutDir, path)
+ if err != nil {
+ panic(err)
+ }
+
+ if isRel {
+ // The path is in the soong out dir so indicate that in the relative path.
+ return filepath.Join("out/soong", rel)
+ }
+
+ // Check to see if the path is relative to the top level out dir.
+ outDir := filepath.Dir(soongOutDir)
+ rel, isRel, err = maybeRelErr(outDir, path)
+ if err != nil {
+ panic(err)
+ }
+
+ if isRel {
+ // The path is in the out dir so indicate that in the relative path.
+ return filepath.Join("out", rel)
+ }
+
+ // This should never happen.
+ panic(fmt.Errorf("internal error: absolute path %s is not relative to the out dir %s", path, outDir))
+}
+
+// StringPathsRelativeToTop creates a slice of strings where each string is the result of applying
+// StringPathRelativeToTop to the corresponding string path in the input slice.
+//
+// This is provided for processing paths that have already been converted into a string, e.g. paths
+// in AndroidMkEntries structures. As a result it needs to be supplied the soong output dir against
+// which it can try and relativize paths. PathsRelativeToTop must be used for process Paths objects.
+func StringPathsRelativeToTop(soongOutDir string, paths []string) []string {
+ var result []string
+ for _, path := range paths {
+ relative := StringPathRelativeToTop(soongOutDir, path)
+ result = append(result, relative)
+ }
+ return result
+}
diff --git a/android/variable.go b/android/variable.go
index be12a0a..a5e9ab4 100644
--- a/android/variable.go
+++ b/android/variable.go
@@ -314,6 +314,11 @@
DirectedRecoverySnapshot bool `json:",omitempty"`
RecoverySnapshotModules map[string]bool `json:",omitempty"`
+ VendorSnapshotDirsIncluded []string `json:",omitempty"`
+ VendorSnapshotDirsExcluded []string `json:",omitempty"`
+ RecoverySnapshotDirsExcluded []string `json:",omitempty"`
+ RecoverySnapshotDirsIncluded []string `json:",omitempty"`
+
BoardVendorSepolicyDirs []string `json:",omitempty"`
BoardOdmSepolicyDirs []string `json:",omitempty"`
BoardReqdMaskPolicy []string `json:",omitempty"`
diff --git a/android/visibility_test.go b/android/visibility_test.go
index eb4071e..fdf18ce 100644
--- a/android/visibility_test.go
+++ b/android/visibility_test.go
@@ -1166,17 +1166,17 @@
RunTest(t)
if test.effectiveVisibility != nil {
- checkEffectiveVisibility(result, test.effectiveVisibility)
+ checkEffectiveVisibility(t, result, test.effectiveVisibility)
}
})
}
}
-func checkEffectiveVisibility(result *TestResult, effectiveVisibility map[qualifiedModuleName][]string) {
+func checkEffectiveVisibility(t *testing.T, result *TestResult, effectiveVisibility map[qualifiedModuleName][]string) {
for moduleName, expectedRules := range effectiveVisibility {
rule := effectiveVisibilityRules(result.Config, moduleName)
stringRules := rule.Strings()
- result.AssertDeepEquals("effective rules mismatch", expectedRules, stringRules)
+ AssertDeepEquals(t, "effective rules mismatch", expectedRules, stringRules)
}
}
diff --git a/apex/Android.bp b/apex/Android.bp
index 8a2edeb..1890b89 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -25,6 +25,7 @@
"deapexer.go",
"key.go",
"prebuilt.go",
+ "testing.go",
"vndk.go",
],
testSrcs: [
diff --git a/apex/allowed_deps.txt b/apex/allowed_deps.txt
index 170302c..154b9aa 100644
--- a/apex/allowed_deps.txt
+++ b/apex/allowed_deps.txt
@@ -408,6 +408,7 @@
libring(minSdkVersion:29)
libring-core(minSdkVersion:29)
librustc_demangle.rust_sysroot(minSdkVersion:29)
+libruy_static(minSdkVersion:30)
libsdk_proto(minSdkVersion:30)
libsfplugin_ccodec_utils(minSdkVersion:29)
libsonivoxwithoutjet(minSdkVersion:29)
diff --git a/apex/apex.go b/apex/apex.go
index e5b5c92..3db20f4 100644
--- a/apex/apex.go
+++ b/apex/apex.go
@@ -102,6 +102,9 @@
// List of prebuilt files that are embedded inside this APEX bundle.
Prebuilts []string
+ // List of platform_compat_config files that are embedded inside this APEX bundle.
+ Compat_configs []string
+
// List of BPF programs inside this APEX bundle.
Bpfs []string
@@ -549,20 +552,21 @@
}
var (
- androidAppTag = dependencyTag{name: "androidApp", payload: true}
- bpfTag = dependencyTag{name: "bpf", payload: true}
- certificateTag = dependencyTag{name: "certificate"}
- executableTag = dependencyTag{name: "executable", payload: true}
- fsTag = dependencyTag{name: "filesystem", payload: true}
- bootImageTag = dependencyTag{name: "bootImage", payload: true}
- javaLibTag = dependencyTag{name: "javaLib", payload: true}
- jniLibTag = dependencyTag{name: "jniLib", payload: true}
- keyTag = dependencyTag{name: "key"}
- prebuiltTag = dependencyTag{name: "prebuilt", payload: true}
- rroTag = dependencyTag{name: "rro", payload: true}
- sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
- testForTag = dependencyTag{name: "test for"}
- testTag = dependencyTag{name: "test", payload: true}
+ androidAppTag = dependencyTag{name: "androidApp", payload: true}
+ bpfTag = dependencyTag{name: "bpf", payload: true}
+ certificateTag = dependencyTag{name: "certificate"}
+ executableTag = dependencyTag{name: "executable", payload: true}
+ fsTag = dependencyTag{name: "filesystem", payload: true}
+ bootImageTag = dependencyTag{name: "bootImage", payload: true}
+ compatConfigsTag = dependencyTag{name: "compatConfig", payload: true}
+ javaLibTag = dependencyTag{name: "javaLib", payload: true}
+ jniLibTag = dependencyTag{name: "jniLib", payload: true}
+ keyTag = dependencyTag{name: "key"}
+ prebuiltTag = dependencyTag{name: "prebuilt", payload: true}
+ rroTag = dependencyTag{name: "rro", payload: true}
+ sharedLibTag = dependencyTag{name: "sharedLib", payload: true}
+ testForTag = dependencyTag{name: "test for"}
+ testTag = dependencyTag{name: "test", payload: true}
)
// TODO(jiyong): shorten this function signature
@@ -737,6 +741,7 @@
ctx.AddFarVariationDependencies(commonVariation, javaLibTag, a.properties.Java_libs...)
ctx.AddFarVariationDependencies(commonVariation, bpfTag, a.properties.Bpfs...)
ctx.AddFarVariationDependencies(commonVariation, fsTag, a.properties.Filesystems...)
+ ctx.AddFarVariationDependencies(commonVariation, compatConfigsTag, a.properties.Compat_configs...)
if a.artApex {
// With EMMA_INSTRUMENT_FRAMEWORK=true the ART boot image includes jacoco library.
@@ -1735,10 +1740,14 @@
case prebuiltTag:
if prebuilt, ok := child.(prebuilt_etc.PrebuiltEtcModule); ok {
filesInfo = append(filesInfo, apexFileForPrebuiltEtc(ctx, prebuilt, depName))
- } else if prebuilt, ok := child.(java.PlatformCompatConfigIntf); ok {
- filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, prebuilt, depName))
} else {
- ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc and not a platform_compat_config module", depName)
+ ctx.PropertyErrorf("prebuilts", "%q is not a prebuilt_etc module", depName)
+ }
+ case compatConfigsTag:
+ if compatConfig, ok := child.(java.PlatformCompatConfigIntf); ok {
+ filesInfo = append(filesInfo, apexFileForCompatConfig(ctx, compatConfig, depName))
+ } else {
+ ctx.PropertyErrorf("compat_configs", "%q is not a platform_compat_config module", depName)
}
case testTag:
if ccTest, ok := child.(*cc.Module); ok {
diff --git a/apex/apex_test.go b/apex/apex_test.go
index 08f54f7..21cf5df 100644
--- a/apex/apex_test.go
+++ b/apex/apex_test.go
@@ -127,6 +127,96 @@
config.TestProductVariables.Unbundled_build = proptools.BoolPtr(true)
}
+var emptyFixtureFactory = android.NewFixtureFactory(&buildDir)
+
+var apexFixtureFactory = android.NewFixtureFactory(
+ &buildDir,
+ // General preparers in alphabetical order as test infrastructure will enforce correct
+ // registration order.
+ android.PrepareForTestWithAndroidBuildComponents,
+ bpf.PrepareForTestWithBpf,
+ cc.PrepareForTestWithCcBuildComponents,
+ java.PrepareForTestWithJavaDefaultModules,
+ prebuilt_etc.PrepareForTestWithPrebuiltEtc,
+ rust.PrepareForTestWithRustDefaultModules,
+ sh.PrepareForTestWithShBuildComponents,
+
+ PrepareForTestWithApexBuildComponents,
+
+ // Additional apex test specific preparers.
+ android.FixtureAddTextFile("system/sepolicy/Android.bp", `
+ filegroup {
+ name: "myapex-file_contexts",
+ srcs: [
+ "apex/myapex-file_contexts",
+ ],
+ }
+ `),
+ android.FixtureMergeMockFs(android.MockFS{
+ "a.java": nil,
+ "PrebuiltAppFoo.apk": nil,
+ "PrebuiltAppFooPriv.apk": nil,
+ "build/make/target/product/security": nil,
+ "apex_manifest.json": nil,
+ "AndroidManifest.xml": nil,
+ "system/sepolicy/apex/myapex-file_contexts": nil,
+ "system/sepolicy/apex/myapex.updatable-file_contexts": nil,
+ "system/sepolicy/apex/myapex2-file_contexts": nil,
+ "system/sepolicy/apex/otherapex-file_contexts": nil,
+ "system/sepolicy/apex/com.android.vndk-file_contexts": nil,
+ "system/sepolicy/apex/com.android.vndk.current-file_contexts": nil,
+ "mylib.cpp": nil,
+ "mytest.cpp": nil,
+ "mytest1.cpp": nil,
+ "mytest2.cpp": nil,
+ "mytest3.cpp": nil,
+ "myprebuilt": nil,
+ "my_include": nil,
+ "foo/bar/MyClass.java": nil,
+ "prebuilt.jar": nil,
+ "prebuilt.so": nil,
+ "vendor/foo/devkeys/test.x509.pem": nil,
+ "vendor/foo/devkeys/test.pk8": nil,
+ "testkey.x509.pem": nil,
+ "testkey.pk8": nil,
+ "testkey.override.x509.pem": nil,
+ "testkey.override.pk8": nil,
+ "vendor/foo/devkeys/testkey.avbpubkey": nil,
+ "vendor/foo/devkeys/testkey.pem": nil,
+ "NOTICE": nil,
+ "custom_notice": nil,
+ "custom_notice_for_static_lib": nil,
+ "testkey2.avbpubkey": nil,
+ "testkey2.pem": nil,
+ "myapex-arm64.apex": nil,
+ "myapex-arm.apex": nil,
+ "myapex.apks": nil,
+ "frameworks/base/api/current.txt": nil,
+ "framework/aidl/a.aidl": nil,
+ "build/make/core/proguard.flags": nil,
+ "build/make/core/proguard_basic_keeps.flags": nil,
+ "dummy.txt": nil,
+ "baz": nil,
+ "bar/baz": nil,
+ "testdata/baz": nil,
+ "AppSet.apks": nil,
+ "foo.rs": nil,
+ "libfoo.jar": nil,
+ "libbar.jar": nil,
+ },
+ ),
+
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.DeviceVndkVersion = proptools.StringPtr("current")
+ variables.DefaultAppCertificate = proptools.StringPtr("vendor/foo/devkeys/test")
+ variables.CertificateOverrides = []string{"myapex_keytest:myapex.certificate.override"}
+ variables.Platform_sdk_codename = proptools.StringPtr("Q")
+ variables.Platform_sdk_final = proptools.BoolPtr(false)
+ variables.Platform_version_active_codenames = []string{"Q"}
+ variables.Platform_vndk_version = proptools.StringPtr("VER")
+ }),
+)
+
func testApexContext(_ *testing.T, bp string, handlers ...testCustomizer) (*android.TestContext, android.Config) {
bp = bp + `
filegroup {
@@ -432,7 +522,7 @@
}
rust_binary {
- name: "foo.rust",
+ name: "foo.rust",
srcs: ["foo.rs"],
rlibs: ["libfoo.rlib.rust"],
dylibs: ["libfoo.dylib.rust"],
@@ -440,14 +530,14 @@
}
rust_library_rlib {
- name: "libfoo.rlib.rust",
+ name: "libfoo.rlib.rust",
srcs: ["foo.rs"],
crate_name: "foo",
apex_available: ["myapex"],
}
rust_library_dylib {
- name: "libfoo.dylib.rust",
+ name: "libfoo.dylib.rust",
srcs: ["foo.rs"],
crate_name: "foo",
apex_available: ["myapex"],
@@ -642,14 +732,12 @@
fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
ensureListContains(t, fullDepsInfo, " myjar(minSdkVersion:(no version)) <- myapex")
- ensureListContains(t, fullDepsInfo, " mylib(minSdkVersion:(no version)) <- myapex")
ensureListContains(t, fullDepsInfo, " mylib2(minSdkVersion:(no version)) <- mylib")
ensureListContains(t, fullDepsInfo, " myotherjar(minSdkVersion:(no version)) <- myjar")
ensureListContains(t, fullDepsInfo, " mysharedjar(minSdkVersion:(no version)) (external) <- myjar")
flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex", "android_common_myapex_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
ensureListContains(t, flatDepsInfo, "myjar(minSdkVersion:(no version))")
- ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
ensureListContains(t, flatDepsInfo, "mylib2(minSdkVersion:(no version))")
ensureListContains(t, flatDepsInfo, "myotherjar(minSdkVersion:(no version))")
ensureListContains(t, flatDepsInfo, "mysharedjar(minSdkVersion:(no version)) (external)")
@@ -1148,13 +1236,9 @@
ensureNotContains(t, libFooStubsLdFlags, "libbar.so")
fullDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/fulllist.txt").Args["content"], "\\n")
- ensureListContains(t, fullDepsInfo, " mylib(minSdkVersion:(no version)) <- myapex2")
- ensureListContains(t, fullDepsInfo, " libbaz(minSdkVersion:(no version)) <- mylib")
ensureListContains(t, fullDepsInfo, " libfoo(minSdkVersion:(no version)) (external) <- mylib")
flatDepsInfo := strings.Split(ctx.ModuleForTests("myapex2", "android_common_myapex2_image").Output("depsinfo/flatlist.txt").Args["content"], "\\n")
- ensureListContains(t, flatDepsInfo, "mylib(minSdkVersion:(no version))")
- ensureListContains(t, flatDepsInfo, "libbaz(minSdkVersion:(no version))")
ensureListContains(t, flatDepsInfo, "libfoo(minSdkVersion:(no version)) (external)")
}
@@ -1228,9 +1312,10 @@
}
-func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
- ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
- bp := `
+var prepareForTestOfRuntimeApexWithHwasan = android.GroupFixturePreparers(
+ cc.PrepareForTestWithCcBuildComponents,
+ PrepareForTestWithApexBuildComponents,
+ android.FixtureAddTextFile("bionic/apex/Android.bp", `
apex {
name: "com.android.runtime",
key: "com.android.runtime.key",
@@ -1243,7 +1328,12 @@
public_key: "testkey.avbpubkey",
private_key: "testkey.pem",
}
+ `),
+ android.FixtureAddFile("system/sepolicy/apex/com.android.runtime-file_contexts", nil),
+)
+func TestRuntimeApexShouldInstallHwasanIfLibcDependsOnIt(t *testing.T) {
+ result := emptyFixtureFactory.Extend(prepareForTestOfRuntimeApexWithHwasan).RunTestWithBp(t, `
cc_library {
name: "libc",
no_libcrt: true,
@@ -1270,12 +1360,8 @@
sanitize: {
never: true,
},
- }
- `
- // override bp to use hard-coded names: com.android.runtime and libc
- fs["Android.bp"] = []byte(bp)
- fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
- })
+ } `)
+ ctx := result.TestContext
ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
"lib64/bionic/libc.so",
@@ -1293,21 +1379,12 @@
}
func TestRuntimeApexShouldInstallHwasanIfHwaddressSanitized(t *testing.T) {
- ctx := testApex(t, "", func(fs map[string][]byte, config android.Config) {
- bp := `
- apex {
- name: "com.android.runtime",
- key: "com.android.runtime.key",
- native_shared_libs: ["libc"],
- updatable: false,
- }
-
- apex_key {
- name: "com.android.runtime.key",
- public_key: "testkey.avbpubkey",
- private_key: "testkey.pem",
- }
-
+ result := emptyFixtureFactory.Extend(
+ prepareForTestOfRuntimeApexWithHwasan,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.SanitizeDevice = []string{"hwaddress"}
+ }),
+ ).RunTestWithBp(t, `
cc_library {
name: "libc",
no_libcrt: true,
@@ -1331,13 +1408,8 @@
never: true,
},
}
- `
- // override bp to use hard-coded names: com.android.runtime and libc
- fs["Android.bp"] = []byte(bp)
- fs["system/sepolicy/apex/com.android.runtime-file_contexts"] = nil
-
- config.TestProductVariables.SanitizeDevice = []string{"hwaddress"}
- })
+ `)
+ ctx := result.TestContext
ensureExactContents(t, ctx, "com.android.runtime", "android_common_hwasan_com.android.runtime_image", []string{
"lib64/bionic/libc.so",
@@ -1961,7 +2033,7 @@
java_library {
name: "myjar",
srcs: ["foo/bar/MyClass.java"],
- sdk_version: "core_platform",
+ sdk_version: "test_current",
apex_available: ["myapex"],
}
`,
@@ -2008,13 +2080,16 @@
java_library {
name: "myjar",
srcs: ["foo/bar/MyClass.java"],
- sdk_version: "core_platform",
+ sdk_version: "test_current",
apex_available: ["myapex"],
}
`,
},
{
- name: "Updatable apex with non-stable transitive dep",
+ name: "Updatable apex with non-stable transitive dep",
+ // This is not actually detecting that the transitive dependency is unstable, rather it is
+ // detecting that the transitive dependency is building against a wider API surface than the
+ // module that depends on it is using.
expectedError: "compiles against Android API, but dependency \"transitive-jar\" is compiling against private API.",
bp: `
apex {
@@ -5914,11 +5989,13 @@
}
func TestCompatConfig(t *testing.T) {
- ctx := testApex(t, `
+ result := apexFixtureFactory.
+ Extend(java.PrepareForTestWithPlatformCompatConfig).
+ RunTestWithBp(t, `
apex {
name: "myapex",
key: "myapex.key",
- prebuilts: ["myjar-platform-compat-config"],
+ compat_configs: ["myjar-platform-compat-config"],
java_libs: ["myjar"],
updatable: false,
}
@@ -5942,6 +6019,7 @@
apex_available: [ "myapex" ],
}
`)
+ ctx := result.TestContext
ensureExactContents(t, ctx, "myapex", "android_common_myapex_image", []string{
"etc/compatconfig/myjar-platform-compat-config.xml",
"javalib/myjar.jar",
diff --git a/apex/builder.go b/apex/builder.go
index 2663a67..da800d4 100644
--- a/apex/builder.go
+++ b/apex/builder.go
@@ -926,9 +926,15 @@
return !externalDep
}
+ // Skip dependencies that are only available to APEXes; they are developed with updatability
+ // in mind and don't need manual approval.
+ if to.(android.ApexModule).NotAvailableForPlatform() {
+ return !externalDep
+ }
+
depTag := ctx.OtherModuleDependencyTag(to)
+ // Check to see if dependency been marked to skip the dependency check
if skipDepCheck, ok := depTag.(android.SkipApexAllowedDependenciesCheck); ok && skipDepCheck.SkipApexAllowedDependenciesCheck() {
- // Check to see if dependency been marked to skip the dependency check
return !externalDep
}
diff --git a/apex/testing.go b/apex/testing.go
new file mode 100644
index 0000000..e662cad
--- /dev/null
+++ b/apex/testing.go
@@ -0,0 +1,22 @@
+// 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 apex
+
+import "android/soong/android"
+
+var PrepareForTestWithApexBuildComponents = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerApexBuildComponents),
+ android.FixtureRegisterWithContext(registerApexKeyBuildComponents),
+)
diff --git a/bazel/Android.bp b/bazel/Android.bp
index 117fd46..b7c185a 100644
--- a/bazel/Android.bp
+++ b/bazel/Android.bp
@@ -12,6 +12,7 @@
],
testSrcs: [
"aquery_test.go",
+ "properties_test.go",
],
pluginFor: [
"soong_build",
diff --git a/bazel/cquery/Android.bp b/bazel/cquery/Android.bp
new file mode 100644
index 0000000..3a71e9c
--- /dev/null
+++ b/bazel/cquery/Android.bp
@@ -0,0 +1,14 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+bootstrap_go_package {
+ name: "soong-cquery",
+ pkgPath: "android/soong/bazel/cquery",
+ srcs: [
+ "request_type.go",
+ ],
+ pluginFor: [
+ "soong_build",
+ ],
+}
diff --git a/bazel/cquery/request_type.go b/bazel/cquery/request_type.go
new file mode 100644
index 0000000..864db3d
--- /dev/null
+++ b/bazel/cquery/request_type.go
@@ -0,0 +1,110 @@
+package cquery
+
+import (
+ "strings"
+)
+
+var (
+ GetOutputFiles RequestType = &getOutputFilesRequestType{}
+ GetCcObjectFiles RequestType = &getCcObjectFilesRequestType{}
+ GetOutputFilesAndCcObjectFiles RequestType = &getOutputFilesAndCcObjectFilesType{}
+)
+
+type GetOutputFilesAndCcObjectFiles_Result struct {
+ OutputFiles []string
+ CcObjectFiles []string
+}
+
+var RequestTypes []RequestType = []RequestType{
+ GetOutputFiles, GetCcObjectFiles, GetOutputFilesAndCcObjectFiles}
+
+type RequestType interface {
+ // Name returns a string name for this request type. Such request type names must be unique,
+ // and must only consist of alphanumeric characters.
+ Name() string
+
+ // StarlarkFunctionBody returns a straark function body to process this request type.
+ // The returned string is the body of a Starlark function which obtains
+ // all request-relevant information about a target and returns a string containing
+ // this information.
+ // The function should have the following properties:
+ // - `target` is the only parameter to this function (a configured target).
+ // - The return value must be a string.
+ // - The function body should not be indented outside of its own scope.
+ StarlarkFunctionBody() string
+
+ // ParseResult returns a value obtained by parsing the result of the request's Starlark function.
+ // The given rawString must correspond to the string output which was created by evaluating the
+ // Starlark given in StarlarkFunctionBody.
+ // The type of this value depends on the request type; it is up to the caller to
+ // cast to the correct type.
+ ParseResult(rawString string) interface{}
+}
+
+type getOutputFilesRequestType struct{}
+
+func (g getOutputFilesRequestType) Name() string {
+ return "getOutputFiles"
+}
+
+func (g getOutputFilesRequestType) StarlarkFunctionBody() string {
+ return "return ', '.join([f.path for f in target.files.to_list()])"
+}
+
+func (g getOutputFilesRequestType) ParseResult(rawString string) interface{} {
+ return strings.Split(rawString, ", ")
+}
+
+type getCcObjectFilesRequestType struct{}
+
+func (g getCcObjectFilesRequestType) Name() string {
+ return "getCcObjectFiles"
+}
+
+func (g getCcObjectFilesRequestType) StarlarkFunctionBody() string {
+ return `
+result = []
+linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
+
+for linker_input in linker_inputs:
+ for library in linker_input.libraries:
+ for object in library.objects:
+ result += [object.path]
+return ', '.join(result)`
+}
+
+func (g getCcObjectFilesRequestType) ParseResult(rawString string) interface{} {
+ return strings.Split(rawString, ", ")
+}
+
+type getOutputFilesAndCcObjectFilesType struct{}
+
+func (g getOutputFilesAndCcObjectFilesType) Name() string {
+ return "getOutputFilesAndCcObjectFiles"
+}
+
+func (g getOutputFilesAndCcObjectFilesType) StarlarkFunctionBody() string {
+ return `
+outputFiles = [f.path for f in target.files.to_list()]
+
+ccObjectFiles = []
+linker_inputs = providers(target)["CcInfo"].linking_context.linker_inputs.to_list()
+
+for linker_input in linker_inputs:
+ for library in linker_input.libraries:
+ for object in library.objects:
+ ccObjectFiles += [object.path]
+return ', '.join(outputFiles) + "|" + ', '.join(ccObjectFiles)`
+}
+
+func (g getOutputFilesAndCcObjectFilesType) ParseResult(rawString string) interface{} {
+ var outputFiles []string
+ var ccObjects []string
+
+ splitString := strings.Split(rawString, "|")
+ outputFilesString := splitString[0]
+ ccObjectsString := splitString[1]
+ outputFiles = strings.Split(outputFilesString, ", ")
+ ccObjects = strings.Split(ccObjectsString, ", ")
+ return GetOutputFilesAndCcObjectFiles_Result{outputFiles, ccObjects}
+}
diff --git a/bazel/properties.go b/bazel/properties.go
index a5ffa55..abdc107 100644
--- a/bazel/properties.go
+++ b/bazel/properties.go
@@ -14,22 +14,10 @@
package bazel
-import "fmt"
-
-type bazelModuleProperties struct {
- // The label of the Bazel target replacing this Soong module.
- Label string
-
- // If true, bp2build will generate the converted Bazel target for this module.
- Bp2build_available bool
-}
-
-// Properties contains common module properties for Bazel migration purposes.
-type Properties struct {
- // In USE_BAZEL_ANALYSIS=1 mode, this represents the Bazel target replacing
- // this Soong module.
- Bazel_module bazelModuleProperties
-}
+import (
+ "fmt"
+ "sort"
+)
// BazelTargetModuleProperties contain properties and metadata used for
// Blueprint to BUILD file conversion.
@@ -66,6 +54,28 @@
}
}
+func UniqueBazelLabels(originalLabels []Label) []Label {
+ uniqueLabelsSet := make(map[Label]bool)
+ for _, l := range originalLabels {
+ uniqueLabelsSet[l] = true
+ }
+ var uniqueLabels []Label
+ for l, _ := range uniqueLabelsSet {
+ uniqueLabels = append(uniqueLabels, l)
+ }
+ sort.SliceStable(uniqueLabels, func(i, j int) bool {
+ return uniqueLabels[i].Label < uniqueLabels[j].Label
+ })
+ return uniqueLabels
+}
+
+func UniqueBazelLabelList(originalLabelList LabelList) LabelList {
+ var uniqueLabelList LabelList
+ uniqueLabelList.Includes = UniqueBazelLabels(originalLabelList.Includes)
+ uniqueLabelList.Excludes = UniqueBazelLabels(originalLabelList.Excludes)
+ return uniqueLabelList
+}
+
// StringListAttribute corresponds to the string_list Bazel attribute type with
// support for additional metadata, like configurations.
type StringListAttribute struct {
diff --git a/bazel/properties_test.go b/bazel/properties_test.go
new file mode 100644
index 0000000..0fcb904
--- /dev/null
+++ b/bazel/properties_test.go
@@ -0,0 +1,89 @@
+// 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 bazel
+
+import (
+ "reflect"
+ "testing"
+)
+
+func TestUniqueBazelLabels(t *testing.T) {
+ testCases := []struct {
+ originalLabels []Label
+ expectedUniqueLabels []Label
+ }{
+ {
+ originalLabels: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "a"},
+ {Label: "c"},
+ },
+ expectedUniqueLabels: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "c"},
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualUniqueLabels := UniqueBazelLabels(tc.originalLabels)
+ if !reflect.DeepEqual(tc.expectedUniqueLabels, actualUniqueLabels) {
+ t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabels, actualUniqueLabels)
+ }
+ }
+}
+
+func TestUniqueBazelLabelList(t *testing.T) {
+ testCases := []struct {
+ originalLabelList LabelList
+ expectedUniqueLabelList LabelList
+ }{
+ {
+ originalLabelList: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "a"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ expectedUniqueLabelList: LabelList{
+ Includes: []Label{
+ {Label: "a"},
+ {Label: "b"},
+ {Label: "c"},
+ },
+ Excludes: []Label{
+ {Label: "x"},
+ {Label: "y"},
+ {Label: "z"},
+ },
+ },
+ },
+ }
+ for _, tc := range testCases {
+ actualUniqueLabelList := UniqueBazelLabelList(tc.originalLabelList)
+ if !reflect.DeepEqual(tc.expectedUniqueLabelList, actualUniqueLabelList) {
+ t.Fatalf("Expected %v, got %v", tc.expectedUniqueLabelList, actualUniqueLabelList)
+ }
+ }
+}
diff --git a/bp2build/Android.bp b/bp2build/Android.bp
index 99d706c..c74f902 100644
--- a/bp2build/Android.bp
+++ b/bp2build/Android.bp
@@ -11,6 +11,7 @@
"build_conversion.go",
"bzl_conversion.go",
"configurability.go",
+ "constants.go",
"conversion.go",
"metrics.go",
],
diff --git a/bp2build/bp2build.go b/bp2build/bp2build.go
index 7169d7e..97a5137 100644
--- a/bp2build/bp2build.go
+++ b/bp2build/bp2build.go
@@ -22,7 +22,7 @@
// The Bazel bp2build code generator is responsible for writing .bzl files that are equivalent to
// Android.bp files that are capable of being built with Bazel.
-func Codegen(ctx CodegenContext) CodegenMetrics {
+func Codegen(ctx *CodegenContext) CodegenMetrics {
outputDir := android.PathForOutput(ctx, "bp2build")
android.RemoveAllOutputDir(outputDir)
diff --git a/bp2build/build_conversion.go b/bp2build/build_conversion.go
index 7fa4996..9c98c76 100644
--- a/bp2build/build_conversion.go
+++ b/bp2build/build_conversion.go
@@ -99,9 +99,10 @@
}
type CodegenContext struct {
- config android.Config
- context android.Context
- mode CodegenMode
+ config android.Config
+ context android.Context
+ mode CodegenMode
+ additionalDeps []string
}
func (c *CodegenContext) Mode() CodegenMode {
@@ -137,14 +138,26 @@
}
}
-func (ctx CodegenContext) AddNinjaFileDeps(...string) {}
-func (ctx CodegenContext) Config() android.Config { return ctx.config }
-func (ctx CodegenContext) Context() android.Context { return ctx.context }
+// AddNinjaFileDeps adds dependencies on the specified files to be added to the ninja manifest. The
+// primary builder will be rerun whenever the specified files are modified. Allows us to fulfill the
+// PathContext interface in order to add dependencies on hand-crafted BUILD files. Note: must also
+// call AdditionalNinjaDeps and add them manually to the ninja file.
+func (ctx *CodegenContext) AddNinjaFileDeps(deps ...string) {
+ ctx.additionalDeps = append(ctx.additionalDeps, deps...)
+}
+
+// AdditionalNinjaDeps returns additional ninja deps added by CodegenContext
+func (ctx *CodegenContext) AdditionalNinjaDeps() []string {
+ return ctx.additionalDeps
+}
+
+func (ctx *CodegenContext) Config() android.Config { return ctx.config }
+func (ctx *CodegenContext) Context() android.Context { return ctx.context }
// NewCodegenContext creates a wrapper context that conforms to PathContext for
// writing BUILD files in the output directory.
-func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) CodegenContext {
- return CodegenContext{
+func NewCodegenContext(config android.Config, context android.Context, mode CodegenMode) *CodegenContext {
+ return &CodegenContext{
context: context,
config: config,
mode: mode,
@@ -163,12 +176,14 @@
return attributes
}
-func GenerateBazelTargets(ctx CodegenContext) (map[string]BazelTargets, CodegenMetrics) {
+func GenerateBazelTargets(ctx *CodegenContext) (map[string]BazelTargets, CodegenMetrics) {
buildFileToTargets := make(map[string]BazelTargets)
+ buildFileToAppend := make(map[string]bool)
// Simple metrics tracking for bp2build
- totalModuleCount := 0
- ruleClassCount := make(map[string]int)
+ metrics := CodegenMetrics{
+ RuleClassCount: make(map[string]int),
+ }
bpCtx := ctx.Context()
bpCtx.VisitAllModules(func(m blueprint.Module) {
@@ -177,13 +192,29 @@
switch ctx.Mode() {
case Bp2Build:
- if b, ok := m.(android.BazelTargetModule); !ok {
- // Only include regular Soong modules (non-BazelTargetModules) into the total count.
- totalModuleCount += 1
- return
+ if b, ok := m.(android.Bazelable); ok && b.HasHandcraftedLabel() {
+ metrics.handCraftedTargetCount += 1
+ metrics.TotalModuleCount += 1
+ pathToBuildFile := getBazelPackagePath(b)
+ // We are using the entire contents of handcrafted build file, so if multiple targets within
+ // a package have handcrafted targets, we only want to include the contents one time.
+ if _, exists := buildFileToAppend[pathToBuildFile]; exists {
+ return
+ }
+ var err error
+ t, err = getHandcraftedBuildContent(ctx, b, pathToBuildFile)
+ if err != nil {
+ panic(fmt.Errorf("Error converting %s: %s", bpCtx.ModuleName(m), err))
+ }
+ // TODO(b/181575318): currently we append the whole BUILD file, let's change that to do
+ // something more targeted based on the rule type and target
+ buildFileToAppend[pathToBuildFile] = true
+ } else if btm, ok := m.(android.BazelTargetModule); ok {
+ t = generateBazelTarget(bpCtx, m, btm)
+ metrics.RuleClassCount[t.ruleClass] += 1
} else {
- t = generateBazelTarget(bpCtx, m, b)
- ruleClassCount[t.ruleClass] += 1
+ metrics.TotalModuleCount += 1
+ return
}
case QueryView:
// Blocklist certain module types from being generated.
@@ -200,17 +231,34 @@
buildFileToTargets[dir] = append(buildFileToTargets[dir], t)
})
- metrics := CodegenMetrics{
- TotalModuleCount: totalModuleCount,
- RuleClassCount: ruleClassCount,
- }
-
return buildFileToTargets, metrics
}
-func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module, b android.BazelTargetModule) BazelTarget {
- ruleClass := b.RuleClass()
- bzlLoadLocation := b.BzlLoadLocation()
+func getBazelPackagePath(b android.Bazelable) string {
+ label := b.HandcraftedLabel()
+ pathToBuildFile := strings.TrimPrefix(label, "//")
+ pathToBuildFile = strings.Split(pathToBuildFile, ":")[0]
+ return pathToBuildFile
+}
+
+func getHandcraftedBuildContent(ctx *CodegenContext, b android.Bazelable, pathToBuildFile string) (BazelTarget, error) {
+ p := android.ExistentPathForSource(ctx, pathToBuildFile, HandcraftedBuildFileName)
+ if !p.Valid() {
+ return BazelTarget{}, fmt.Errorf("Could not find file %q for handcrafted target.", pathToBuildFile)
+ }
+ c, err := b.GetBazelBuildFileContents(ctx.Config(), pathToBuildFile, HandcraftedBuildFileName)
+ if err != nil {
+ return BazelTarget{}, err
+ }
+ // TODO(b/181575318): once this is more targeted, we need to include name, rule class, etc
+ return BazelTarget{
+ content: c,
+ }, nil
+}
+
+func generateBazelTarget(ctx bpToBuildContext, m blueprint.Module, btm android.BazelTargetModule) BazelTarget {
+ ruleClass := btm.RuleClass()
+ bzlLoadLocation := btm.BzlLoadLocation()
// extract the bazel attributes from the module.
props := getBuildProperties(ctx, m)
diff --git a/bp2build/build_conversion_test.go b/bp2build/build_conversion_test.go
index aa4fc1d..89acbe9 100644
--- a/bp2build/build_conversion_test.go
+++ b/bp2build/build_conversion_test.go
@@ -1221,3 +1221,157 @@
}
}
}
+
+func TestCombineBuildFilesBp2buildTargets(t *testing.T) {
+ testCases := []struct {
+ description string
+ moduleTypeUnderTest string
+ moduleTypeUnderTestFactory android.ModuleFactory
+ moduleTypeUnderTestBp2BuildMutator func(android.TopDownMutatorContext)
+ preArchMutators []android.RegisterMutatorFunc
+ depsMutators []android.RegisterMutatorFunc
+ bp string
+ expectedBazelTargets []string
+ fs map[string]string
+ dir string
+ }{
+ {
+ description: "filegroup bazel_module.label",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ bp: `filegroup {
+ name: "fg_foo",
+ bazel_module: { label: "//other:fg_foo" },
+}`,
+ expectedBazelTargets: []string{
+ `// BUILD file`,
+ },
+ fs: map[string]string{
+ "other/BUILD.bazel": `// BUILD file`,
+ },
+ },
+ {
+ description: "multiple bazel_module.label same BUILD",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ bp: `filegroup {
+ name: "fg_foo",
+ bazel_module: { label: "//other:fg_foo" },
+}
+
+filegroup {
+ name: "foo",
+ bazel_module: { label: "//other:foo" },
+}`,
+ expectedBazelTargets: []string{
+ `// BUILD file`,
+ },
+ fs: map[string]string{
+ "other/BUILD.bazel": `// BUILD file`,
+ },
+ },
+ {
+ description: "filegroup bazel_module.label and bp2build",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ bp: `filegroup {
+ name: "fg_foo",
+ bazel_module: {
+ label: "//other:fg_foo",
+ bp2build_available: true,
+ },
+}`,
+ expectedBazelTargets: []string{
+ `filegroup(
+ name = "fg_foo",
+)`,
+ `// BUILD file`,
+ },
+ fs: map[string]string{
+ "other/BUILD.bazel": `// BUILD file`,
+ },
+ },
+ {
+ description: "filegroup bazel_module.label and filegroup bp2build",
+ moduleTypeUnderTest: "filegroup",
+ moduleTypeUnderTestFactory: android.FileGroupFactory,
+ moduleTypeUnderTestBp2BuildMutator: android.FilegroupBp2Build,
+ bp: `filegroup {
+ name: "fg_foo",
+ bazel_module: {
+ label: "//other:fg_foo",
+ },
+}
+
+filegroup {
+ name: "fg_bar",
+ bazel_module: {
+ bp2build_available: true,
+ },
+}`,
+ expectedBazelTargets: []string{
+ `filegroup(
+ name = "fg_bar",
+)`,
+ `// BUILD file`,
+ },
+ fs: map[string]string{
+ "other/BUILD.bazel": `// BUILD file`,
+ },
+ },
+ }
+
+ dir := "."
+ for _, testCase := range testCases {
+ fs := make(map[string][]byte)
+ toParse := []string{
+ "Android.bp",
+ }
+ for f, content := range testCase.fs {
+ if strings.HasSuffix(f, "Android.bp") {
+ toParse = append(toParse, f)
+ }
+ fs[f] = []byte(content)
+ }
+ config := android.TestConfig(buildDir, nil, testCase.bp, fs)
+ ctx := android.NewTestContext(config)
+ ctx.RegisterModuleType(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestFactory)
+ for _, m := range testCase.depsMutators {
+ ctx.DepsBp2BuildMutators(m)
+ }
+ ctx.RegisterBp2BuildMutator(testCase.moduleTypeUnderTest, testCase.moduleTypeUnderTestBp2BuildMutator)
+ ctx.RegisterForBazelConversion()
+
+ _, errs := ctx.ParseFileList(dir, toParse)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+ _, errs = ctx.ResolveDependencies(config)
+ if Errored(t, testCase.description, errs) {
+ continue
+ }
+
+ checkDir := dir
+ if testCase.dir != "" {
+ checkDir = testCase.dir
+ }
+ bazelTargets := generateBazelTargetsForDir(NewCodegenContext(config, *ctx.Context, Bp2Build), checkDir)
+ if actualCount, expectedCount := len(bazelTargets), len(testCase.expectedBazelTargets); actualCount != expectedCount {
+ t.Errorf("%s: Expected %d bazel target, got %d\n%s", testCase.description, expectedCount, actualCount, bazelTargets)
+ } else {
+ for i, target := range bazelTargets {
+ if w, g := testCase.expectedBazelTargets[i], target.content; w != g {
+ t.Errorf(
+ "%s: Expected generated Bazel target to be '%s', got '%s'",
+ testCase.description,
+ w,
+ g,
+ )
+ }
+ }
+ }
+ }
+}
diff --git a/bp2build/constants.go b/bp2build/constants.go
new file mode 100644
index 0000000..23bca83
--- /dev/null
+++ b/bp2build/constants.go
@@ -0,0 +1,25 @@
+// Copyright 2020 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 bp2build
+
+var (
+ // When both a BUILD and BUILD.bazel file are exist in the same package, the BUILD.bazel file will
+ // be preferred for use within a Bazel build.
+
+ // The file name used for automatically generated files. Files with this name are ignored by git.
+ GeneratedBuildFileName = "BUILD"
+ // The file name used for hand-crafted build targets.
+ HandcraftedBuildFileName = "BUILD.bazel"
+)
diff --git a/bp2build/conversion.go b/bp2build/conversion.go
index 1225f2b..7877bb8 100644
--- a/bp2build/conversion.go
+++ b/bp2build/conversion.go
@@ -24,9 +24,9 @@
// Write top level files: WORKSPACE and BUILD. These files are empty.
files = append(files, newFile("", "WORKSPACE", ""))
// Used to denote that the top level directory is a package.
- files = append(files, newFile("", "BUILD", ""))
+ files = append(files, newFile("", GeneratedBuildFileName, ""))
- files = append(files, newFile(bazelRulesSubDir, "BUILD", ""))
+ files = append(files, newFile(bazelRulesSubDir, GeneratedBuildFileName, ""))
if mode == QueryView {
// These files are only used for queryview.
@@ -47,7 +47,14 @@
files := make([]BazelFile, 0, len(buildToTargets))
for _, dir := range android.SortedStringKeys(buildToTargets) {
targets := buildToTargets[dir]
- sort.Slice(targets, func(i, j int) bool { return targets[i].name < targets[j].name })
+ sort.Slice(targets, func(i, j int) bool {
+ // this will cover all bp2build generated targets
+ if targets[i].name < targets[j].name {
+ return true
+ }
+ // give a strict ordering to content from hand-crafted targets
+ return targets[i].content < targets[j].content
+ })
content := soongModuleLoad
if mode == Bp2Build {
content = `# This file was automatically generated by bp2build for the Bazel migration project.
@@ -62,7 +69,7 @@
content += "\n\n"
}
content += targets.String()
- files = append(files, newFile(dir, "BUILD", content))
+ files = append(files, newFile(dir, GeneratedBuildFileName, content))
}
return files
}
diff --git a/bp2build/metrics.go b/bp2build/metrics.go
index 916129f..65b06c6 100644
--- a/bp2build/metrics.go
+++ b/bp2build/metrics.go
@@ -13,6 +13,9 @@
// Counts of generated Bazel targets per Bazel rule class
RuleClassCount map[string]int
+
+ // Total number of handcrafted targets
+ handCraftedTargetCount int
}
// Print the codegen metrics to stdout.
@@ -24,7 +27,8 @@
generatedTargetCount += count
}
fmt.Printf(
- "[bp2build] Generated %d total BUILD targets from %d Android.bp modules.\n",
+ "[bp2build] Generated %d total BUILD targets and included %d handcrafted BUILD targets from %d Android.bp modules.\n",
generatedTargetCount,
+ metrics.handCraftedTargetCount,
metrics.TotalModuleCount)
}
diff --git a/bp2build/testing.go b/bp2build/testing.go
index bd75a8f..a15a4a5 100644
--- a/bp2build/testing.go
+++ b/bp2build/testing.go
@@ -175,7 +175,7 @@
}
// Helper method for tests to easily access the targets in a dir.
-func generateBazelTargetsForDir(codegenCtx CodegenContext, dir string) BazelTargets {
+func generateBazelTargetsForDir(codegenCtx *CodegenContext, dir string) BazelTargets {
buildFileToTargets, _ := GenerateBazelTargets(codegenCtx)
return buildFileToTargets[dir]
}
diff --git a/cc/cc.go b/cc/cc.go
index c335dac..cab7459 100644
--- a/cc/cc.go
+++ b/cc/cc.go
@@ -1605,7 +1605,7 @@
// Returns true if Bazel was successfully used for the analysis of this module.
func (c *Module) maybeGenerateBazelActions(actx android.ModuleContext) bool {
- bazelModuleLabel := c.GetBazelLabel()
+ bazelModuleLabel := c.GetBazelLabel(actx, c)
bazelActionsUsed := false
if c.bazelHandler != nil && actx.Config().BazelContext.BazelEnabled() && len(bazelModuleLabel) > 0 {
bazelActionsUsed = c.bazelHandler.generateBazelBuildActions(actx, bazelModuleLabel)
diff --git a/cc/cc_test.go b/cc/cc_test.go
index 7d9fa47..16ae7ee 100644
--- a/cc/cc_test.go
+++ b/cc/cc_test.go
@@ -222,7 +222,7 @@
for _, o := range ld.Inputs {
objs = append(objs, o.Base())
}
- result.AssertArrayString("libTest inputs", []string{"foo.o", "bar.o"}, objs)
+ android.AssertArrayString(t, "libTest inputs", []string{"foo.o", "bar.o"}, objs)
}
func TestVendorSrc(t *testing.T) {
@@ -3429,7 +3429,7 @@
).RunTestWithBp(t, bp)
libfoo := result.Module("libfoo", "android_arm64_armv8-a_static").(*Module)
- result.AssertStringListContains("cppflags", libfoo.flags.Local.CppFlags, "-DBAR")
+ android.AssertStringListContains(t, "cppflags", libfoo.flags.Local.CppFlags, "-DBAR")
}
func TestEmptyWholeStaticLibsAllowMissingDependencies(t *testing.T) {
@@ -3452,12 +3452,12 @@
).RunTestWithBp(t, bp)
libbar := result.ModuleForTests("libbar", "android_arm64_armv8-a_static").Output("libbar.a")
- result.AssertDeepEquals("libbar rule", android.ErrorRule, libbar.Rule)
+ android.AssertDeepEquals(t, "libbar rule", android.ErrorRule, libbar.Rule)
- result.AssertStringDoesContain("libbar error", libbar.Args["error"], "missing dependencies: libmissing")
+ android.AssertStringDoesContain(t, "libbar error", libbar.Args["error"], "missing dependencies: libmissing")
libfoo := result.ModuleForTests("libfoo", "android_arm64_armv8-a_static").Output("libfoo.a")
- result.AssertStringListContains("libfoo.a dependencies", libfoo.Inputs.Strings(), libbar.Output.String())
+ android.AssertStringListContains(t, "libfoo.a dependencies", libfoo.Inputs.Strings(), libbar.Output.String())
}
func TestInstallSharedLibs(t *testing.T) {
diff --git a/cc/library.go b/cc/library.go
index 6a3b876..22a36c6 100644
--- a/cc/library.go
+++ b/cc/library.go
@@ -415,38 +415,39 @@
func (handler *staticLibraryBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- outputPaths, objPaths, ok := bazelCtx.GetAllFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
- if ok {
- if len(outputPaths) != 1 {
- // TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
- // We should support this.
- ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths)
- return false
- }
- outputFilePath := android.PathForBazelOut(ctx, outputPaths[0])
- handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
-
- objFiles := make(android.Paths, len(objPaths))
- for i, objPath := range objPaths {
- objFiles[i] = android.PathForBazelOut(ctx, objPath)
- }
- objects := Objects{
- objFiles: objFiles,
- }
-
- ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
- StaticLibrary: outputFilePath,
- ReuseObjects: objects,
- Objects: objects,
-
- // TODO(cparsons): Include transitive static libraries in this provider to support
- // static libraries with deps.
- TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
- Direct(outputFilePath).
- Build(),
- })
- handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
+ outputPaths, objPaths, ok := bazelCtx.GetOutputFilesAndCcObjectFiles(label, ctx.Arch().ArchType)
+ if !ok {
+ return ok
}
+ if len(outputPaths) != 1 {
+ // TODO(cparsons): This is actually expected behavior for static libraries with no srcs.
+ // We should support this.
+ ctx.ModuleErrorf("expected exactly one output file for '%s', but got %s", label, objPaths)
+ return false
+ }
+ outputFilePath := android.PathForBazelOut(ctx, outputPaths[0])
+ handler.module.outputFile = android.OptionalPathForPath(outputFilePath)
+
+ objFiles := make(android.Paths, len(objPaths))
+ for i, objPath := range objPaths {
+ objFiles[i] = android.PathForBazelOut(ctx, objPath)
+ }
+ objects := Objects{
+ objFiles: objFiles,
+ }
+
+ ctx.SetProvider(StaticLibraryInfoProvider, StaticLibraryInfo{
+ StaticLibrary: outputFilePath,
+ ReuseObjects: objects,
+ Objects: objects,
+
+ // TODO(cparsons): Include transitive static libraries in this provider to support
+ // static libraries with deps.
+ TransitiveStaticLibrariesForOrdering: android.NewDepSetBuilder(android.TOPOLOGICAL).
+ Direct(outputFilePath).
+ Build(),
+ })
+ handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
return ok
}
diff --git a/cc/object.go b/cc/object.go
index 126bd65..f9e6d2d 100644
--- a/cc/object.go
+++ b/cc/object.go
@@ -53,17 +53,8 @@
}
func (handler *objectBazelHandler) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
- bazelCtx := ctx.Config().BazelContext
- objPaths, ok := bazelCtx.GetCcObjectFiles(label, ctx.Arch().ArchType)
- if ok {
- if len(objPaths) != 1 {
- ctx.ModuleErrorf("expected exactly one object file for '%s', but got %s", label, objPaths)
- return false
- }
-
- handler.module.outputFile = android.OptionalPathForPath(android.PathForBazelOut(ctx, objPaths[0]))
- }
- return ok
+ // TODO(b/181794963): restore mixed builds once cc_object incompatibility resolved
+ return false
}
type ObjectLinkerProperties struct {
diff --git a/cc/sanitize.go b/cc/sanitize.go
index 8218d97..cd09e6e 100644
--- a/cc/sanitize.go
+++ b/cc/sanitize.go
@@ -404,12 +404,6 @@
s.Diag.Cfi = boolPtr(false)
}
- // Also disable CFI for arm32 until b/35157333 is fixed.
- if ctx.Arch().ArchType == android.Arm {
- s.Cfi = boolPtr(false)
- s.Diag.Cfi = boolPtr(false)
- }
-
// HWASan requires AArch64 hardware feature (top-byte-ignore).
if ctx.Arch().ArchType != android.Arm64 {
s.Hwaddress = nil
diff --git a/cc/snapshot_prebuilt.go b/cc/snapshot_prebuilt.go
index f9aea0c..bbb8896 100644
--- a/cc/snapshot_prebuilt.go
+++ b/cc/snapshot_prebuilt.go
@@ -18,6 +18,7 @@
// snapshot mutators and snapshot information maps which are also defined in this file.
import (
+ "path/filepath"
"strings"
"android/soong/android"
@@ -45,9 +46,9 @@
// directory, such as device/, vendor/, etc.
//
// For a given snapshot (e.g., vendor, recovery, etc.) if
- // isProprietaryPath(dir) returns true, then the module in dir will be
- // built from sources.
- isProprietaryPath(dir string) bool
+ // isProprietaryPath(dir, deviceConfig) returns true, then the module in dir
+ // will be built from sources.
+ isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool
// Whether to include VNDK in the snapshot for this image.
includeVndk() bool
@@ -82,6 +83,31 @@
type vendorSnapshotImage struct{}
type recoverySnapshotImage struct{}
+type directoryMap map[string]bool
+
+var (
+ // Modules under following directories are ignored. They are OEM's and vendor's
+ // proprietary modules(device/, kernel/, vendor/, and hardware/).
+ defaultDirectoryExcludedMap = directoryMap{
+ "device": true,
+ "hardware": true,
+ "kernel": true,
+ "vendor": true,
+ }
+
+ // Modules under following directories are included as they are in AOSP,
+ // although hardware/ and kernel/ are normally for vendor's own.
+ defaultDirectoryIncludedMap = directoryMap{
+ "kernel/configs": true,
+ "kernel/prebuilts": true,
+ "kernel/tests": true,
+ "hardware/interfaces": true,
+ "hardware/libhardware": true,
+ "hardware/libhardware_legacy": true,
+ "hardware/ril": true,
+ }
+)
+
func (vendorSnapshotImage) init(ctx android.RegistrationContext) {
ctx.RegisterSingletonType("vendor-snapshot", VendorSnapshotSingleton)
ctx.RegisterModuleType("vendor_snapshot", vendorSnapshotFactory)
@@ -107,8 +133,25 @@
return m.IsVndkPrivate()
}
-func (vendorSnapshotImage) isProprietaryPath(dir string) bool {
- return isVendorProprietaryPath(dir)
+func isDirectoryExcluded(dir string, excludedMap directoryMap, includedMap directoryMap) bool {
+ if dir == "." || dir == "/" {
+ return false
+ }
+ if includedMap[dir] {
+ return false
+ } else if excludedMap[dir] {
+ return true
+ } else if defaultDirectoryIncludedMap[dir] {
+ return false
+ } else if defaultDirectoryExcludedMap[dir] {
+ return true
+ } else {
+ return isDirectoryExcluded(filepath.Dir(dir), excludedMap, includedMap)
+ }
+}
+
+func (vendorSnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+ return isDirectoryExcluded(dir, deviceConfig.VendorSnapshotDirsExcludedMap(), deviceConfig.VendorSnapshotDirsIncludedMap())
}
// vendor snapshot includes static/header libraries with vndk: {enabled: true}.
@@ -172,8 +215,8 @@
return false
}
-func (recoverySnapshotImage) isProprietaryPath(dir string) bool {
- return isRecoveryProprietaryPath(dir)
+func (recoverySnapshotImage) isProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+ return isDirectoryExcluded(dir, deviceConfig.RecoverySnapshotDirsExcludedMap(), deviceConfig.RecoverySnapshotDirsIncludedMap())
}
// recovery snapshot does NOT treat vndk specially.
diff --git a/cc/snapshot_utils.go b/cc/snapshot_utils.go
index c50ef45..c32fa36 100644
--- a/cc/snapshot_utils.go
+++ b/cc/snapshot_utils.go
@@ -80,7 +80,7 @@
}
for _, image := range []snapshotImage{vendorSnapshotImageSingleton, recoverySnapshotImageSingleton} {
- if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir()), apexInfo, image) {
+ if isSnapshotAware(ctx.DeviceConfig(), m, image.isProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()), apexInfo, image) {
return true
}
}
diff --git a/cc/testing.go b/cc/testing.go
index 6840ef4..d8adc61 100644
--- a/cc/testing.go
+++ b/cc/testing.go
@@ -649,8 +649,11 @@
// The preparer to include if running a cc related test for linux bionic.
var PrepareForTestOnLinuxBionic = android.GroupFixturePreparers(
- // Enable linux bionic.
- android.FixtureAddTextFile(linuxBionicDefaultsPath, withLinuxBionic()),
+ // Enable linux bionic
+ //
+ // Can be used after PrepareForTestWithCcDefaultModules to override its default behavior of
+ // disabling linux bionic, hence why this uses FixtureOverrideTextFile.
+ android.FixtureOverrideTextFile(linuxBionicDefaultsPath, withLinuxBionic()),
)
// The preparer to include if running a cc related test for fuchsia.
diff --git a/cc/vendor_snapshot.go b/cc/vendor_snapshot.go
index 7077b71..fdd1fec 100644
--- a/cc/vendor_snapshot.go
+++ b/cc/vendor_snapshot.go
@@ -90,73 +90,24 @@
fake bool
}
-var (
- // Modules under following directories are ignored. They are OEM's and vendor's
- // proprietary modules(device/, kernel/, vendor/, and hardware/).
- vendorProprietaryDirs = []string{
- "device",
- "kernel",
- "vendor",
- "hardware",
- }
-
- // Modules under following directories are ignored. They are OEM's and vendor's
- // proprietary modules(device/, kernel/, vendor/, and hardware/).
- recoveryProprietaryDirs = []string{
- "device",
- "hardware",
- "kernel",
- "vendor",
- }
-
- // Modules under following directories are included as they are in AOSP,
- // although hardware/ and kernel/ are normally for vendor's own.
- aospDirsUnderProprietary = []string{
- "kernel/configs",
- "kernel/prebuilts",
- "kernel/tests",
- "hardware/interfaces",
- "hardware/libhardware",
- "hardware/libhardware_legacy",
- "hardware/ril",
- }
-)
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
-// device/, vendor/, etc.
-func isVendorProprietaryPath(dir string) bool {
- return isProprietaryPath(dir, vendorProprietaryDirs)
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on vendor snapshot configuration
+// Examples: device/, vendor/
+func isVendorProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+ return VendorSnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
}
-func isRecoveryProprietaryPath(dir string) bool {
- return isProprietaryPath(dir, recoveryProprietaryDirs)
-}
-
-// Determine if a dir under source tree is an SoC-owned proprietary directory, such as
-// device/, vendor/, etc.
-func isProprietaryPath(dir string, proprietaryDirs []string) bool {
- for _, p := range proprietaryDirs {
- if strings.HasPrefix(dir, p) {
- // filter out AOSP defined directories, e.g. hardware/interfaces/
- aosp := false
- for _, p := range aospDirsUnderProprietary {
- if strings.HasPrefix(dir, p) {
- aosp = true
- break
- }
- }
- if !aosp {
- return true
- }
- }
- }
- return false
+// Determine if a dir under source tree is an SoC-owned proprietary directory based
+// on recovery snapshot configuration
+// Examples: device/, vendor/
+func isRecoveryProprietaryPath(dir string, deviceConfig android.DeviceConfig) bool {
+ return RecoverySnapshotSingleton().(*snapshotSingleton).image.isProprietaryPath(dir, deviceConfig)
}
func isVendorProprietaryModule(ctx android.BaseModuleContext) bool {
// Any module in a vendor proprietary path is a vendor proprietary
// module.
- if isVendorProprietaryPath(ctx.ModuleDir()) {
+ if isVendorProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
return true
}
@@ -177,7 +128,7 @@
// Any module in a recovery proprietary path is a recovery proprietary
// module.
- if isRecoveryProprietaryPath(ctx.ModuleDir()) {
+ if isRecoveryProprietaryPath(ctx.ModuleDir(), ctx.DeviceConfig()) {
return true
}
@@ -513,7 +464,7 @@
}
moduleDir := ctx.ModuleDir(module)
- inProprietaryPath := c.image.isProprietaryPath(moduleDir)
+ inProprietaryPath := c.image.isProprietaryPath(moduleDir, ctx.DeviceConfig())
apexInfo := ctx.ModuleProvider(module, android.ApexInfoProvider).(android.ApexInfo)
if c.image.excludeFromSnapshot(m) {
diff --git a/cmd/soong_build/main.go b/cmd/soong_build/main.go
index 4586f44..8322fbe 100644
--- a/cmd/soong_build/main.go
+++ b/cmd/soong_build/main.go
@@ -198,7 +198,6 @@
if err != nil {
panic(err)
}
- extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
// Run the loading and analysis pipeline to prepare the graph of regular
// Modules parsed from Android.bp files, and the BazelTargetModules mapped
@@ -215,6 +214,9 @@
// 1:1 mapping for each module.
metrics.Print()
+ extraNinjaDeps = append(extraNinjaDeps, codegenContext.AdditionalNinjaDeps()...)
+ extraNinjaDepsString := strings.Join(extraNinjaDeps, " \\\n ")
+
// Workarounds to support running bp2build in a clean AOSP checkout with no
// prior builds, and exiting early as soon as the BUILD files get generated,
// therefore not creating build.ninja files that soong_ui and callers of
diff --git a/cmd/soong_build/queryview.go b/cmd/soong_build/queryview.go
index 0a77d67..edc8a42 100644
--- a/cmd/soong_build/queryview.go
+++ b/cmd/soong_build/queryview.go
@@ -22,7 +22,7 @@
"path/filepath"
)
-func createBazelQueryView(ctx bp2build.CodegenContext, bazelQueryViewDir string) error {
+func createBazelQueryView(ctx *bp2build.CodegenContext, bazelQueryViewDir string) error {
ruleShims := bp2build.CreateRuleShims(android.ModuleTypeFactories())
// Ignore metrics reporting for queryview, since queryview is already a full-repo
diff --git a/dexpreopt/dexpreopt.go b/dexpreopt/dexpreopt.go
index fdb00bd..4999bc7 100644
--- a/dexpreopt/dexpreopt.go
+++ b/dexpreopt/dexpreopt.go
@@ -261,21 +261,17 @@
} else if module.EnforceUsesLibraries {
// Generate command that saves target SDK version in a shell variable.
- if module.ManifestPath != nil {
- rule.Command().Text(`target_sdk_version="$(`).
- Tool(globalSoong.ManifestCheck).
- Flag("--extract-target-sdk-version").
- Input(module.ManifestPath).
- Text(`)"`)
- } else {
- // No manifest to extract targetSdkVersion from, hope that DexJar is an APK
- rule.Command().Text(`target_sdk_version="$(`).
- Tool(globalSoong.Aapt).
- Flag("dump badging").
- Input(module.DexPath).
- Text(`| grep "targetSdkVersion" | sed -n "s/targetSdkVersion:'\(.*\)'/\1/p"`).
- Text(`)"`)
+ manifestOrApk := module.ManifestPath
+ if manifestOrApk == nil {
+ // No manifest to extract targetSdkVersion from, hope that dexjar is an APK.
+ manifestOrApk = module.DexPath
}
+ rule.Command().Text(`target_sdk_version="$(`).
+ Tool(globalSoong.ManifestCheck).
+ Flag("--extract-target-sdk-version").
+ Input(manifestOrApk).
+ FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt")).
+ Text(`)"`)
// Generate command that saves host and target class loader context in shell variables.
clc, paths := ComputeClassLoaderContext(module.ClassLoaderContexts)
diff --git a/etc/prebuilt_etc_test.go b/etc/prebuilt_etc_test.go
index 6727e59..f800c48 100644
--- a/etc/prebuilt_etc_test.go
+++ b/etc/prebuilt_etc_test.go
@@ -15,7 +15,6 @@
package etc
import (
- "io/ioutil"
"os"
"path/filepath"
"testing"
@@ -23,33 +22,12 @@
"android/soong/android"
)
-var buildDir string
-
-func setUp() {
- var err error
- buildDir, err = ioutil.TempDir("", "soong_etc_test")
- if err != nil {
- panic(err)
- }
-}
-
-func tearDown() {
- os.RemoveAll(buildDir)
-}
-
func TestMain(m *testing.M) {
- run := func() int {
- setUp()
- defer tearDown()
-
- return m.Run()
- }
-
- os.Exit(run())
+ os.Exit(m.Run())
}
var prebuiltEtcFixtureFactory = android.NewFixtureFactory(
- &buildDir,
+ nil,
android.PrepareForTestWithArchMutator,
PrepareForTestWithPrebuiltEtc,
android.FixtureMergeMockFs(android.MockFS{
@@ -103,7 +81,7 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- result.AssertStringEquals("output file path", "foo.installed.conf", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "output file path", "foo.installed.conf", p.outputFilePath.Base())
}
func TestPrebuiltEtcGlob(t *testing.T) {
@@ -120,10 +98,10 @@
`)
p := result.Module("my_foo", "android_arm64_armv8-a").(*PrebuiltEtc)
- result.AssertStringEquals("my_foo output file path", "my_foo", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "my_foo output file path", "my_foo", p.outputFilePath.Base())
p = result.Module("my_bar", "android_arm64_armv8-a").(*PrebuiltEtc)
- result.AssertStringEquals("my_bar output file path", "bar.conf", p.outputFilePath.Base())
+ android.AssertStringEquals(t, "my_bar output file path", "bar.conf", p.outputFilePath.Base())
}
func TestPrebuiltEtcAndroidMk(t *testing.T) {
@@ -153,7 +131,7 @@
entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
for k, expectedValue := range expected {
if value, ok := entries.EntryMap[k]; ok {
- result.AssertDeepEquals(k, expectedValue, value)
+ android.AssertDeepEquals(t, k, expectedValue, value)
} else {
t.Errorf("No %s defined, saw %q", k, entries.EntryMap)
}
@@ -170,8 +148,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := buildDir + "/target/product/test_device/system/etc/bar"
- result.AssertStringEquals("install dir", expected, p.installDirPath.String())
+ expected := "out/soong/target/product/test_device/system/etc/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
}
func TestPrebuiltEtcCannotSetRelativeInstallPathAndSubDir(t *testing.T) {
@@ -212,8 +190,8 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := buildDir + "/target/product/test_device/system/usr/share/bar"
- result.AssertStringEquals("install dir", expected, p.installDirPath.String())
+ expected := "out/soong/target/product/test_device/system/usr/share/bar"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
}
func TestPrebuiltUserShareHostInstallDirPath(t *testing.T) {
@@ -227,8 +205,8 @@
buildOS := android.BuildOs.String()
p := result.Module("foo.conf", buildOS+"_common").(*PrebuiltEtc)
- expected := filepath.Join(buildDir, "host", result.Config.PrebuiltOS(), "usr", "share", "bar")
- result.AssertStringEquals("install dir", expected, p.installDirPath.String())
+ expected := filepath.Join("out/soong/host", result.Config.PrebuiltOS(), "usr", "share", "bar")
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
}
func TestPrebuiltFontInstallDirPath(t *testing.T) {
@@ -240,12 +218,12 @@
`)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- expected := buildDir + "/target/product/test_device/system/fonts"
- result.AssertStringEquals("install dir", expected, p.installDirPath.String())
+ expected := "out/soong/target/product/test_device/system/fonts"
+ android.AssertPathRelativeToTopEquals(t, "install dir", expected, p.installDirPath)
}
func TestPrebuiltFirmwareDirPath(t *testing.T) {
- targetPath := buildDir + "/target/product/test_device"
+ targetPath := "out/soong/target/product/test_device"
tests := []struct {
description string
config string
@@ -273,13 +251,13 @@
t.Run(tt.description, func(t *testing.T) {
result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- result.AssertStringEquals("install dir", tt.expectedPath, p.installDirPath.String())
+ android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
})
}
}
func TestPrebuiltDSPDirPath(t *testing.T) {
- targetPath := filepath.Join(buildDir, "/target/product/test_device")
+ targetPath := "out/soong/target/product/test_device"
tests := []struct {
description string
config string
@@ -307,7 +285,7 @@
t.Run(tt.description, func(t *testing.T) {
result := prebuiltEtcFixtureFactory.RunTestWithBp(t, tt.config)
p := result.Module("foo.conf", "android_arm64_armv8-a").(*PrebuiltEtc)
- result.AssertStringEquals("install dir", tt.expectedPath, p.installDirPath.String())
+ android.AssertPathRelativeToTopEquals(t, "install dir", tt.expectedPath, p.installDirPath)
})
}
}
diff --git a/filesystem/bootimg.go b/filesystem/bootimg.go
index 764f045..372a610 100644
--- a/filesystem/bootimg.go
+++ b/filesystem/bootimg.go
@@ -62,6 +62,10 @@
// Optional kernel commandline
Cmdline *string
+ // File that contains bootconfig parameters. This can be set only when `vendor_boot` is true
+ // and `header_version` is greater than or equal to 4.
+ Bootconfig *string `android:"arch_variant,path"`
+
// When set to true, sign the image with avbtool. Default is false.
Use_avb *bool
@@ -153,7 +157,7 @@
if vendor {
flag = "--vendor_cmdline "
}
- cmd.FlagWithArg(flag, "\""+proptools.ShellEscape(cmdline)+"\"")
+ cmd.FlagWithArg(flag, proptools.ShellEscapeIncludingSpaces(cmdline))
}
headerVersion := proptools.String(b.properties.Header_version)
@@ -189,6 +193,19 @@
return output
}
+ bootconfig := proptools.String(b.properties.Bootconfig)
+ if bootconfig != "" {
+ if !vendor {
+ ctx.PropertyErrorf("bootconfig", "requires vendor_boot: true")
+ return output
+ }
+ if verNum < 4 {
+ ctx.PropertyErrorf("bootconfig", "requires header_version: 4 or later")
+ return output
+ }
+ cmd.FlagWithInput("--vendor_bootconfig ", android.PathForModuleSrc(ctx, bootconfig))
+ }
+
flag := "--output "
if vendor {
flag = "--vendor_boot "
@@ -237,3 +254,13 @@
func (b *bootimg) OutputPath() android.Path {
return b.output
}
+
+var _ android.OutputFileProducer = (*bootimg)(nil)
+
+// Implements android.OutputFileProducer
+func (b *bootimg) OutputFiles(tag string) (android.Paths, error) {
+ if tag == "" {
+ return []android.Path{b.output}, nil
+ }
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
diff --git a/filesystem/logical_partition.go b/filesystem/logical_partition.go
index e547203..16b6037 100644
--- a/filesystem/logical_partition.go
+++ b/filesystem/logical_partition.go
@@ -208,3 +208,13 @@
func (l *logicalPartition) OutputPath() android.Path {
return l.output
}
+
+var _ android.OutputFileProducer = (*logicalPartition)(nil)
+
+// Implements android.OutputFileProducer
+func (l *logicalPartition) OutputFiles(tag string) (android.Paths, error) {
+ if tag == "" {
+ return []android.Path{l.output}, nil
+ }
+ return nil, fmt.Errorf("unsupported module reference tag %q", tag)
+}
diff --git a/genrule/genrule.go b/genrule/genrule.go
index 5349906..fc6a44f 100644
--- a/genrule/genrule.go
+++ b/genrule/genrule.go
@@ -227,7 +227,7 @@
// Returns true if information was available from Bazel, false if bazel invocation still needs to occur.
func (c *Module) generateBazelBuildActions(ctx android.ModuleContext, label string) bool {
bazelCtx := ctx.Config().BazelContext
- filePaths, ok := bazelCtx.GetAllFiles(label, ctx.Arch().ArchType)
+ filePaths, ok := bazelCtx.GetOutputFiles(label, ctx.Arch().ArchType)
if ok {
var bazelOutputFiles android.Paths
for _, bazelOutputFile := range filePaths {
@@ -538,7 +538,7 @@
g.outputFiles = outputFiles.Paths()
- bazelModuleLabel := g.GetBazelLabel()
+ bazelModuleLabel := g.GetBazelLabel(ctx, g)
bazelActionsUsed := false
if ctx.Config().BazelContext.BazelEnabled() && len(bazelModuleLabel) > 0 {
bazelActionsUsed = g.generateBazelBuildActions(ctx, bazelModuleLabel)
diff --git a/genrule/genrule_test.go b/genrule/genrule_test.go
index 0873704..d131e94 100644
--- a/genrule/genrule_test.go
+++ b/genrule/genrule_test.go
@@ -15,7 +15,6 @@
package genrule
import (
- "io/ioutil"
"os"
"regexp"
"testing"
@@ -25,33 +24,12 @@
"github.com/google/blueprint/proptools"
)
-var buildDir string
-
-func setUp() {
- var err error
- buildDir, err = ioutil.TempDir("", "genrule_test")
- if err != nil {
- panic(err)
- }
-}
-
-func tearDown() {
- os.RemoveAll(buildDir)
-}
-
func TestMain(m *testing.M) {
- run := func() int {
- setUp()
- defer tearDown()
-
- return m.Run()
- }
-
- os.Exit(run())
+ os.Exit(m.Run())
}
var genruleFixtureFactory = android.NewFixtureFactory(
- &buildDir,
+ nil,
android.PrepareForTestWithArchMutator,
android.PrepareForTestWithDefaults,
@@ -477,7 +455,7 @@
}
gen := result.Module("gen", "").(*Module)
- result.AssertStringEquals("raw commands", test.expect, gen.rawCommands[0])
+ android.AssertStringEquals(t, "raw commands", test.expect, gen.rawCommands[0])
})
}
}
@@ -541,12 +519,11 @@
for _, test := range testcases {
t.Run(test.name, func(t *testing.T) {
- subResult := result.ResultForSubTest(t)
- gen := subResult.ModuleForTests(test.name, "")
+ gen := result.ModuleForTests(test.name, "")
manifest := android.RuleBuilderSboxProtoForTests(t, gen.Output("genrule.sbox.textproto"))
hash := manifest.Commands[0].GetInputHash()
- subResult.AssertStringEquals("hash", test.expectedHash, hash)
+ android.AssertStringEquals(t, "hash", test.expectedHash, hash)
})
}
}
@@ -573,8 +550,14 @@
cmds: []string{
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
},
- deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
- files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h"},
+ deps: []string{
+ "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+ },
+ files: []string{
+ "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+ },
},
{
name: "shards",
@@ -588,8 +571,16 @@
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in1.txt > __SBOX_SANDBOX_DIR__/out/in1.h' && bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in2.txt > __SBOX_SANDBOX_DIR__/out/in2.h'",
"bash -c '__SBOX_SANDBOX_DIR__/tools/out/bin/tool in3.txt > __SBOX_SANDBOX_DIR__/out/in3.h'",
},
- deps: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
- files: []string{buildDir + "/.intermediates/gen/gen/gensrcs/in1.h", buildDir + "/.intermediates/gen/gen/gensrcs/in2.h", buildDir + "/.intermediates/gen/gen/gensrcs/in3.h"},
+ deps: []string{
+ "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+ },
+ files: []string{
+ "out/soong/.intermediates/gen/gen/gensrcs/in1.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in2.h",
+ "out/soong/.intermediates/gen/gen/gensrcs/in3.h",
+ },
},
}
@@ -615,11 +606,11 @@
}
gen := result.Module("gen", "").(*Module)
- result.AssertDeepEquals("cmd", test.cmds, gen.rawCommands)
+ android.AssertDeepEquals(t, "cmd", test.cmds, gen.rawCommands)
- result.AssertDeepEquals("deps", test.deps, gen.outputDeps.Strings())
+ android.AssertPathsRelativeToTopEquals(t, "deps", test.deps, gen.outputDeps)
- result.AssertDeepEquals("files", test.files, gen.outputFiles.Strings())
+ android.AssertPathsRelativeToTopEquals(t, "files", test.files, gen.outputFiles)
})
}
}
@@ -648,10 +639,10 @@
gen := result.Module("gen", "").(*Module)
expectedCmd := "cp in1 __SBOX_SANDBOX_DIR__/out/out"
- result.AssertStringEquals("cmd", expectedCmd, gen.rawCommands[0])
+ android.AssertStringEquals(t, "cmd", expectedCmd, gen.rawCommands[0])
expectedSrcs := []string{"in1"}
- result.AssertDeepEquals("srcs", expectedSrcs, gen.properties.Srcs)
+ android.AssertDeepEquals(t, "srcs", expectedSrcs, gen.properties.Srcs)
}
func TestGenruleWithBazel(t *testing.T) {
@@ -673,8 +664,8 @@
expectedOutputFiles := []string{"outputbase/execroot/__main__/bazelone.txt",
"outputbase/execroot/__main__/bazeltwo.txt"}
- result.AssertDeepEquals("output files", expectedOutputFiles, gen.outputFiles.Strings())
- result.AssertDeepEquals("output deps", expectedOutputFiles, gen.outputDeps.Strings())
+ android.AssertDeepEquals(t, "output files", expectedOutputFiles, gen.outputFiles.Strings())
+ android.AssertDeepEquals(t, "output deps", expectedOutputFiles, gen.outputDeps.Strings())
}
type testTool struct {
diff --git a/java/androidmk_test.go b/java/androidmk_test.go
index e758a92..3477956 100644
--- a/java/androidmk_test.go
+++ b/java/androidmk_test.go
@@ -135,7 +135,10 @@
}
func TestJavaSdkLibrary_RequireXmlPermissionFile(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo-shared_library", "foo-no_shared_library"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo-shared_library",
srcs: ["a.java"],
@@ -148,7 +151,7 @@
`)
// Verify the existence of internal modules
- ctx.ModuleForTests("foo-shared_library.xml", "android_common")
+ result.ModuleForTests("foo-shared_library.xml", "android_common")
testCases := []struct {
moduleName string
@@ -158,8 +161,8 @@
{"foo-no_shared_library", nil},
}
for _, tc := range testCases {
- mod := ctx.ModuleForTests(tc.moduleName, "android_common").Module()
- entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
+ mod := result.ModuleForTests(tc.moduleName, "android_common").Module()
+ entries := android.AndroidMkEntriesForTest(t, result.TestContext, mod)[0]
actual := entries.EntryMap["LOCAL_REQUIRED_MODULES"]
if !reflect.DeepEqual(tc.expected, actual) {
t.Errorf("Unexpected required modules - expected: %q, actual: %q", tc.expected, actual)
diff --git a/java/app.go b/java/app.go
index e98fe31..1b6e0e3 100755
--- a/java/app.go
+++ b/java/app.go
@@ -302,7 +302,7 @@
// This check is enforced for "updatable" APKs (including APK-in-APEX).
// b/155209650: until min_sdk_version is properly supported, use sdk_version instead.
// because, sdk_version is overridden by min_sdk_version (if set as smaller)
-// and linkType is checked with dependencies so we can be sure that the whole dependency tree
+// and sdkLinkType is checked with dependencies so we can be sure that the whole dependency tree
// will meet the requirements.
func (a *AndroidApp) checkJniLibsSdkVersion(ctx android.ModuleContext, minSdkVersion sdkVersion) {
// It's enough to check direct JNI deps' sdk_version because all transitive deps from JNI deps are checked in cc.checkLinkType()
@@ -812,6 +812,13 @@
depsInfo := android.DepNameToDepInfoMap{}
a.WalkPayloadDeps(ctx, func(ctx android.ModuleContext, from blueprint.Module, to android.ApexModule, externalDep bool) bool {
depName := to.Name()
+
+ // Skip dependencies that are only available to APEXes; they are developed with updatability
+ // in mind and don't need manual approval.
+ if to.(android.ApexModule).NotAvailableForPlatform() {
+ return true
+ }
+
if info, exist := depsInfo[depName]; exist {
info.From = append(info.From, from.Name())
info.IsExternal = info.IsExternal && externalDep
@@ -1274,10 +1281,13 @@
u.usesLibraryProperties.Enforce_uses_libs = &enforce
}
-// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against the ones specified
-// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the manifest.
-func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
- outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
+// verifyUsesLibraries checks the <uses-library> tags in the manifest against the ones specified
+// in the `uses_libs`/`optional_uses_libs` properties. The input can be either an XML manifest, or
+// an APK with the manifest embedded in it (manifest_check will know which one it is by the file
+// extension: APKs are supposed to end with '.apk').
+func (u *usesLibrary) verifyUsesLibraries(ctx android.ModuleContext, inputFile android.Path,
+ outputFile android.WritablePath) android.Path {
+
statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
// Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the
@@ -1285,15 +1295,19 @@
// non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
// various unrelated reasons, such as a failure to get manifest from an APK).
if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
- return manifest
+ return inputFile
}
rule := android.NewRuleBuilder(pctx, ctx)
cmd := rule.Command().BuiltTool("manifest_check").
Flag("--enforce-uses-libraries").
- Input(manifest).
+ Input(inputFile).
FlagWithOutput("--enforce-uses-libraries-status ", statusFile).
- FlagWithOutput("-o ", outputFile)
+ FlagWithInput("--aapt ", ctx.Config().HostToolPath(ctx, "aapt"))
+
+ if outputFile != nil {
+ cmd.FlagWithOutput("-o ", outputFile)
+ }
if dexpreopt.GetGlobalConfig(ctx).RelaxUsesLibraryCheck {
cmd.Flag("--enforce-uses-libraries-relax")
@@ -1308,35 +1322,20 @@
}
rule.Build("verify_uses_libraries", "verify <uses-library>")
-
return outputFile
}
-// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the ones specified
-// in the uses_libs and optional_uses_libs properties. It returns the path to a copy of the APK.
+// verifyUsesLibrariesManifest checks the <uses-library> tags in an AndroidManifest.xml against
+// the build system and returns the path to a copy of the manifest.
+func (u *usesLibrary) verifyUsesLibrariesManifest(ctx android.ModuleContext, manifest android.Path) android.Path {
+ outputFile := android.PathForModuleOut(ctx, "manifest_check", "AndroidManifest.xml")
+ return u.verifyUsesLibraries(ctx, manifest, outputFile)
+}
+
+// verifyUsesLibrariesAPK checks the <uses-library> tags in the manifest of an APK against the build
+// system and returns the path to a copy of the APK.
func (u *usesLibrary) verifyUsesLibrariesAPK(ctx android.ModuleContext, apk android.Path) android.Path {
+ u.verifyUsesLibraries(ctx, apk, nil) // for APKs manifest_check does not write output file
outputFile := android.PathForModuleOut(ctx, "verify_uses_libraries", apk.Base())
- statusFile := dexpreopt.UsesLibrariesStatusFile(ctx)
-
- // Disable verify_uses_libraries check if dexpreopt is globally disabled. Without dexpreopt the
- // check is not necessary, and although it is good to have, it is difficult to maintain on
- // non-linux build platforms where dexpreopt is generally disabled (the check may fail due to
- // various unrelated reasons, such as a failure to get manifest from an APK).
- if dexpreopt.GetGlobalConfig(ctx).DisablePreopt {
- return apk
- }
-
- rule := android.NewRuleBuilder(pctx, ctx)
- aapt := ctx.Config().HostToolPath(ctx, "aapt")
- rule.Command().
- Textf("aapt_binary=%s", aapt.String()).Implicit(aapt).
- Textf(`uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Uses_libs, " ")).
- Textf(`optional_uses_library_names="%s"`, strings.Join(u.usesLibraryProperties.Optional_uses_libs, " ")).
- Textf(`relax_check="%t"`, dexpreopt.GetGlobalConfig(ctx).RelaxUsesLibraryCheck).
- Tool(android.PathForSource(ctx, "build/make/core/verify_uses_libraries.sh")).Input(apk).Output(statusFile)
- rule.Command().Text("cp -f").Input(apk).Output(outputFile)
-
- rule.Build("verify_uses_libraries", "verify <uses-library>")
-
return outputFile
}
diff --git a/java/app_test.go b/java/app_test.go
index 78e1a57..c189ee5 100644
--- a/java/app_test.go
+++ b/java/app_test.go
@@ -28,70 +28,68 @@
"android/soong/cc"
)
-var (
- resourceFiles = []string{
+// testAppConfig is a legacy way of creating a test Config for testing java app modules.
+//
+// See testJava for an explanation as to how to stop using this deprecated method.
+//
+// deprecated
+func testAppConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
+ return testConfig(env, bp, fs)
+}
+
+// testApp runs tests using the javaFixtureFactory
+//
+// See testJava for an explanation as to how to stop using this deprecated method.
+//
+// deprecated
+func testApp(t *testing.T, bp string) *android.TestContext {
+ t.Helper()
+ result := javaFixtureFactory.RunTestWithBp(t, bp)
+ return result.TestContext
+}
+
+func TestApp(t *testing.T) {
+ resourceFiles := []string{
"res/layout/layout.xml",
"res/values/strings.xml",
"res/values-en-rUS/strings.xml",
}
- compiledResourceFiles = []string{
+ compiledResourceFiles := []string{
"aapt2/res/layout_layout.xml.flat",
"aapt2/res/values_strings.arsc.flat",
"aapt2/res/values-en-rUS_strings.arsc.flat",
}
-)
-func testAppConfig(env map[string]string, bp string, fs map[string][]byte) android.Config {
- appFS := map[string][]byte{}
- for k, v := range fs {
- appFS[k] = v
- }
-
- for _, file := range resourceFiles {
- appFS[file] = nil
- }
-
- return testConfig(env, bp, appFS)
-}
-
-func testApp(t *testing.T, bp string) *android.TestContext {
- config := testAppConfig(nil, bp, nil)
-
- ctx := testContext(config)
-
- run(t, ctx, config)
-
- return ctx
-}
-
-func TestApp(t *testing.T) {
for _, moduleType := range []string{"android_app", "android_library"} {
t.Run(moduleType, func(t *testing.T) {
- ctx := testApp(t, moduleType+` {
+ result := javaFixtureFactory.Extend(
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ for _, file := range resourceFiles {
+ fs[file] = nil
+ }
+ }),
+ ).RunTestWithBp(t, moduleType+` {
name: "foo",
srcs: ["a.java"],
sdk_version: "current"
}
`)
- foo := ctx.ModuleForTests("foo", "android_common")
+ foo := result.ModuleForTests("foo", "android_common")
var expectedLinkImplicits []string
manifestFixer := foo.Output("manifest_fixer/AndroidManifest.xml")
expectedLinkImplicits = append(expectedLinkImplicits, manifestFixer.Output.String())
- frameworkRes := ctx.ModuleForTests("framework-res", "android_common")
+ frameworkRes := result.ModuleForTests("framework-res", "android_common")
expectedLinkImplicits = append(expectedLinkImplicits,
frameworkRes.Output("package-res.apk").Output.String())
// Test the mapping from input files to compiled output file names
compile := foo.Output(compiledResourceFiles[0])
- if !reflect.DeepEqual(resourceFiles, compile.Inputs.Strings()) {
- t.Errorf("expected aapt2 compile inputs expected:\n %#v\n got:\n %#v",
- resourceFiles, compile.Inputs.Strings())
- }
+ android.AssertDeepEquals(t, "aapt2 compile inputs", resourceFiles, compile.Inputs.Strings())
compiledResourceOutputs := compile.Outputs.Strings()
sort.Strings(compiledResourceOutputs)
@@ -102,11 +100,8 @@
expectedLinkImplicits = append(expectedLinkImplicits, list.Output.String())
// Check that the link rule uses
- res := ctx.ModuleForTests("foo", "android_common").Output("package-res.apk")
- if !reflect.DeepEqual(expectedLinkImplicits, res.Implicits.Strings()) {
- t.Errorf("expected aapt2 link implicits expected:\n %#v\n got:\n %#v",
- expectedLinkImplicits, res.Implicits.Strings())
- }
+ res := result.ModuleForTests("foo", "android_common").Output("package-res.apk")
+ android.AssertDeepEquals(t, "aapt2 link implicits", expectedLinkImplicits, res.Implicits.Strings())
})
}
}
@@ -2405,13 +2400,13 @@
// Test that all libraries are verified for an APK (library order matters).
verifyApkCmd := prebuilt.Rule("verify_uses_libraries").RuleParams.Command
- verifyApkReqLibs := `uses_library_names="foo com.non.sdk.lib android.test.runner"`
- verifyApkOptLibs := `optional_uses_library_names="bar baz"`
- if !strings.Contains(verifyApkCmd, verifyApkReqLibs) {
- t.Errorf("wanted %q in %q", verifyApkReqLibs, verifyApkCmd)
- }
- if !strings.Contains(verifyApkCmd, verifyApkOptLibs) {
- t.Errorf("wanted %q in %q", verifyApkOptLibs, verifyApkCmd)
+ verifyApkArgs := `--uses-library foo ` +
+ `--uses-library com.non.sdk.lib ` +
+ `--uses-library android.test.runner ` +
+ `--optional-uses-library bar ` +
+ `--optional-uses-library baz `
+ if !strings.Contains(verifyApkCmd, verifyApkArgs) {
+ t.Errorf("wanted %q in %q", verifyApkArgs, verifyApkCmd)
}
// Test that all present libraries are preopted, including implicit SDK dependencies, possibly stubs
diff --git a/java/boot_image.go b/java/boot_image.go
index 8a1e3c9..12e2874 100644
--- a/java/boot_image.go
+++ b/java/boot_image.go
@@ -25,10 +25,18 @@
func init() {
RegisterBootImageBuildComponents(android.InitRegistrationContext)
+
+ android.RegisterSdkMemberType(&bootImageMemberType{
+ SdkMemberTypeBase: android.SdkMemberTypeBase{
+ PropertyName: "boot_images",
+ SupportsSdk: true,
+ },
+ })
}
func RegisterBootImageBuildComponents(ctx android.RegistrationContext) {
ctx.RegisterModuleType("boot_image", bootImageFactory)
+ ctx.RegisterModuleType("prebuilt_boot_image", prebuiltBootImageFactory)
}
type bootImageProperties struct {
@@ -41,7 +49,7 @@
type BootImageModule struct {
android.ModuleBase
android.ApexModuleBase
-
+ android.SdkBase
properties bootImageProperties
}
@@ -50,6 +58,7 @@
m.AddProperties(&m.properties)
android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
android.InitApexModule(m)
+ android.InitSdkAwareModule(m)
return m
}
@@ -138,3 +147,74 @@
// Make it available for other modules.
ctx.SetProvider(BootImageInfoProvider, info)
}
+
+type bootImageMemberType struct {
+ android.SdkMemberTypeBase
+}
+
+func (b *bootImageMemberType) AddDependencies(mctx android.BottomUpMutatorContext, dependencyTag blueprint.DependencyTag, names []string) {
+ mctx.AddVariationDependencies(nil, dependencyTag, names...)
+}
+
+func (b *bootImageMemberType) IsInstance(module android.Module) bool {
+ _, ok := module.(*BootImageModule)
+ return ok
+}
+
+func (b *bootImageMemberType) AddPrebuiltModule(ctx android.SdkMemberContext, member android.SdkMember) android.BpModule {
+ return ctx.SnapshotBuilder().AddPrebuiltModule(member, "prebuilt_boot_image")
+}
+
+func (b *bootImageMemberType) CreateVariantPropertiesStruct() android.SdkMemberProperties {
+ return &bootImageSdkMemberProperties{}
+}
+
+type bootImageSdkMemberProperties struct {
+ android.SdkMemberPropertiesBase
+
+ Image_name string
+}
+
+func (b *bootImageSdkMemberProperties) PopulateFromVariant(ctx android.SdkMemberContext, variant android.Module) {
+ module := variant.(*BootImageModule)
+
+ b.Image_name = module.properties.Image_name
+}
+
+func (b *bootImageSdkMemberProperties) AddToPropertySet(ctx android.SdkMemberContext, propertySet android.BpPropertySet) {
+ if b.Image_name != "" {
+ propertySet.AddProperty("image_name", b.Image_name)
+ }
+}
+
+var _ android.SdkMemberType = (*bootImageMemberType)(nil)
+
+// A prebuilt version of the boot image module.
+//
+// At the moment this is basically just a boot image module that can be used as a prebuilt.
+// Eventually as more functionality is migrated into the boot image module from the singleton then
+// this will diverge.
+type prebuiltBootImageModule struct {
+ BootImageModule
+ prebuilt android.Prebuilt
+}
+
+func (module *prebuiltBootImageModule) Prebuilt() *android.Prebuilt {
+ return &module.prebuilt
+}
+
+func (module *prebuiltBootImageModule) Name() string {
+ return module.prebuilt.Name(module.ModuleBase.Name())
+}
+
+func prebuiltBootImageFactory() android.Module {
+ m := &prebuiltBootImageModule{}
+ m.AddProperties(&m.properties)
+ android.InitAndroidArchModule(m, android.HostAndDeviceSupported, android.MultilibCommon)
+ // This doesn't actually have any prebuilt files of its own so pass a placeholder for the srcs
+ // array.
+ android.InitPrebuiltModule(m, &[]string{"placeholder"})
+ android.InitApexModule(m)
+ android.InitSdkAwareModule(m)
+ return m
+}
diff --git a/java/boot_image_test.go b/java/boot_image_test.go
index a295782..65e590d 100644
--- a/java/boot_image_test.go
+++ b/java/boot_image_test.go
@@ -29,3 +29,12 @@
}
`)
}
+
+func TestUnknownPrebuiltBootImage(t *testing.T) {
+ testJavaError(t, "image_name: Unknown image name \\\"unknown\\\", expected one of art, boot", `
+ prebuilt_boot_image {
+ name: "unknown-boot-image",
+ image_name: "unknown",
+ }
+`)
+}
diff --git a/java/dexpreopt_bootjars_test.go b/java/dexpreopt_bootjars_test.go
index 48bc244..1b910fa 100644
--- a/java/dexpreopt_bootjars_test.go
+++ b/java/dexpreopt_bootjars_test.go
@@ -16,7 +16,6 @@
import (
"path/filepath"
- "reflect"
"sort"
"testing"
@@ -44,17 +43,11 @@
}
`
- config := testConfig(nil, bp, nil)
+ result := javaFixtureFactory.
+ Extend(dexpreopt.FixtureSetBootJars("platform:foo", "platform:bar", "platform:baz")).
+ RunTestWithBp(t, bp)
- pathCtx := android.PathContextForTesting(config)
- dexpreoptConfig := dexpreopt.GlobalConfigForTests(pathCtx)
- dexpreoptConfig.BootJars = android.CreateTestConfiguredJarList([]string{"platform:foo", "platform:bar", "platform:baz"})
- dexpreopt.SetTestGlobalConfig(config, dexpreoptConfig)
-
- ctx := testContext(config)
- run(t, ctx, config)
-
- dexpreoptBootJars := ctx.SingletonForTests("dex_bootjars")
+ dexpreoptBootJars := result.SingletonForTests("dex_bootjars")
rule := dexpreoptBootJars.Output(ruleFile)
for i := range expectedInputs {
@@ -73,13 +66,9 @@
sort.Strings(outputs)
sort.Strings(expectedOutputs)
- if !reflect.DeepEqual(inputs, expectedInputs) {
- t.Errorf("want inputs %q\n got inputs %q", expectedInputs, inputs)
- }
+ android.AssertDeepEquals(t, "inputs", expectedInputs, inputs)
- if !reflect.DeepEqual(outputs, expectedOutputs) {
- t.Errorf("want outputs %q\n got outputs %q", expectedOutputs, outputs)
- }
+ android.AssertDeepEquals(t, "outputs", expectedOutputs, outputs)
}
func TestDexpreoptBootJars(t *testing.T) {
diff --git a/java/hiddenapi_singleton.go b/java/hiddenapi_singleton.go
index 82e8b3f..6ad4ff3 100644
--- a/java/hiddenapi_singleton.go
+++ b/java/hiddenapi_singleton.go
@@ -31,6 +31,8 @@
ctx.RegisterModuleType("hiddenapi_flags", hiddenAPIFlagsFactory)
}
+var PrepareForTestWithHiddenApiBuildComponents = android.FixtureRegisterWithContext(RegisterHiddenApiSingletonComponents)
+
type hiddenAPISingletonPathsStruct struct {
// The path to the CSV file that contains the flags that will be encoded into the dex boot jars.
//
diff --git a/java/hiddenapi_singleton_test.go b/java/hiddenapi_singleton_test.go
index fb63820..f17d436 100644
--- a/java/hiddenapi_singleton_test.go
+++ b/java/hiddenapi_singleton_test.go
@@ -16,68 +16,50 @@
import (
"fmt"
- "strings"
+ "path/filepath"
"testing"
"android/soong/android"
-
"github.com/google/blueprint/proptools"
)
-func testConfigWithBootJars(bp string, bootJars []string, prebuiltHiddenApiDir *string) android.Config {
- config := testConfig(nil, bp, nil)
- config.TestProductVariables.BootJars = android.CreateTestConfiguredJarList(bootJars)
- config.TestProductVariables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir
- return config
+func fixtureSetBootJarsProductVariable(bootJars ...string) android.FixturePreparer {
+ return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.BootJars = android.CreateTestConfiguredJarList(bootJars)
+ })
}
-func testContextWithHiddenAPI(config android.Config) *android.TestContext {
- ctx := testContext(config)
- RegisterHiddenApiSingletonComponents(ctx)
- return ctx
+func fixtureSetPrebuiltHiddenApiDirProductVariable(prebuiltHiddenApiDir *string) android.FixturePreparer {
+ return android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.PrebuiltHiddenApiDir = prebuiltHiddenApiDir
+ })
}
-func testHiddenAPIWithConfig(t *testing.T, config android.Config) *android.TestContext {
- t.Helper()
-
- ctx := testContextWithHiddenAPI(config)
-
- run(t, ctx, config)
- return ctx
-}
-
-func testHiddenAPIBootJars(t *testing.T, bp string, bootJars []string, prebuiltHiddenApiDir *string) (*android.TestContext, android.Config) {
- config := testConfigWithBootJars(bp, bootJars, prebuiltHiddenApiDir)
-
- return testHiddenAPIWithConfig(t, config), config
-}
-
-func testHiddenAPIUnbundled(t *testing.T, unbundled bool) (*android.TestContext, android.Config) {
- config := testConfig(nil, ``, nil)
- config.TestProductVariables.Always_use_prebuilt_sdks = proptools.BoolPtr(unbundled)
-
- return testHiddenAPIWithConfig(t, config), config
-}
+var hiddenApiFixtureFactory = javaFixtureFactory.Extend(PrepareForTestWithHiddenApiBuildComponents)
func TestHiddenAPISingleton(t *testing.T) {
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ ).RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
compile_dex: true,
}
- `, []string{"platform:foo"}, nil)
+ `)
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
hiddenapiRule := hiddenAPI.Rule("hiddenapi")
want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
- if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want)
}
func TestHiddenAPIIndexSingleton(t *testing.T) {
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("bar"),
+ fixtureSetBootJarsProductVariable("platform:foo", "platform:bar"),
+ ).RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -106,9 +88,9 @@
srcs: ["a.java"],
compile_dex: true,
}
- `, []string{"platform:foo", "platform:bar"}, nil)
+ `)
- hiddenAPIIndex := ctx.SingletonForTests("hiddenapi_index")
+ hiddenAPIIndex := result.SingletonForTests("hiddenapi_index")
indexRule := hiddenAPIIndex.Rule("singleton-merged-hiddenapi-index")
CheckHiddenAPIRuleInputs(t, `
.intermediates/bar/android_common/hiddenapi/index.csv
@@ -118,7 +100,7 @@
// Make sure that the foo-hiddenapi-annotations.jar is included in the inputs to the rules that
// creates the index.csv file.
- foo := ctx.ModuleForTests("foo", "android_common")
+ foo := result.ModuleForTests("foo", "android_common")
indexParams := foo.Output("hiddenapi/index.csv")
CheckHiddenAPIRuleInputs(t, `
.intermediates/foo-hiddenapi-annotations/android_common/javac/foo-hiddenapi-annotations.jar
@@ -127,7 +109,15 @@
}
func TestHiddenAPISingletonWithSourceAndPrebuiltPreferredButNoDex(t *testing.T) {
- config := testConfigWithBootJars(`
+ expectedErrorMessage :=
+ "hiddenapi has determined that the source module \"foo\" should be ignored as it has been" +
+ " replaced by the prebuilt module \"prebuilt_foo\" but unfortunately it does not provide a" +
+ " suitable boot dex jar"
+
+ hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ ).ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorMessage)).
+ RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -139,35 +129,30 @@
jars: ["a.jar"],
prefer: true,
}
- `, []string{"platform:foo"}, nil)
-
- ctx := testContextWithHiddenAPI(config)
-
- runWithErrors(t, ctx, config,
- "hiddenapi has determined that the source module \"foo\" should be ignored as it has been"+
- " replaced by the prebuilt module \"prebuilt_foo\" but unfortunately it does not provide a"+
- " suitable boot dex jar")
+ `)
}
func TestHiddenAPISingletonWithPrebuilt(t *testing.T) {
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ ).RunTestWithBp(t, `
java_import {
name: "foo",
jars: ["a.jar"],
compile_dex: true,
}
- `, []string{"platform:foo"}, nil)
+ `)
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
hiddenapiRule := hiddenAPI.Rule("hiddenapi")
want := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
- if !strings.Contains(hiddenapiRule.RuleParams.Command, want) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", want, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, want)
}
func TestHiddenAPISingletonWithPrebuiltUseSource(t *testing.T) {
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ ).RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -180,23 +165,21 @@
compile_dex: true,
prefer: false,
}
- `, []string{"platform:foo"}, nil)
+ `)
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
hiddenapiRule := hiddenAPI.Rule("hiddenapi")
fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
- if !strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg)
prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/dex/foo.jar"
- if strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
- t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg)
}
func TestHiddenAPISingletonWithPrebuiltOverrideSource(t *testing.T) {
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ ).RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -209,19 +192,15 @@
compile_dex: true,
prefer: true,
}
- `, []string{"platform:foo"}, nil)
+ `)
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
hiddenapiRule := hiddenAPI.Rule("hiddenapi")
prebuiltJarArg := "--boot-dex=" + buildDir + "/.intermediates/prebuilt_foo/android_common/dex/foo.jar"
- if !strings.Contains(hiddenapiRule.RuleParams.Command, prebuiltJarArg) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", prebuiltJarArg, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, prebuiltJarArg)
fromSourceJarArg := "--boot-dex=" + buildDir + "/.intermediates/foo/android_common/aligned/foo.jar"
- if strings.Contains(hiddenapiRule.RuleParams.Command, fromSourceJarArg) {
- t.Errorf("Did not expect %s in hiddenapi command, but it was present: %s", fromSourceJarArg, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesNotContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, fromSourceJarArg)
}
func TestHiddenAPISingletonSdks(t *testing.T) {
@@ -232,6 +211,9 @@
systemStub string
testStub string
corePlatformStub string
+
+ // Additional test preparer
+ preparer android.FixturePreparer
}{
{
name: "testBundled",
@@ -240,6 +222,7 @@
systemStub: "android_system_stubs_current",
testStub: "android_test_stubs_current",
corePlatformStub: "legacy.core.platform.api.stubs",
+ preparer: android.GroupFixturePreparers(),
}, {
name: "testUnbundled",
unbundledBuild: true,
@@ -247,33 +230,31 @@
systemStub: "sdk_system_current_android",
testStub: "sdk_test_current_android",
corePlatformStub: "legacy.core.platform.api.stubs",
+ preparer: PrepareForTestWithPrebuiltsOfCurrentApi,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
- ctx, _ := testHiddenAPIUnbundled(t, tc.unbundledBuild)
+ result := hiddenApiFixtureFactory.Extend(
+ tc.preparer,
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.Always_use_prebuilt_sdks = proptools.BoolPtr(tc.unbundledBuild)
+ }),
+ ).RunTest(t)
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
hiddenapiRule := hiddenAPI.Rule("hiddenapi")
wantPublicStubs := "--public-stub-classpath=" + generateSdkDexPath(tc.publicStub, tc.unbundledBuild)
- if !strings.Contains(hiddenapiRule.RuleParams.Command, wantPublicStubs) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantPublicStubs, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantPublicStubs)
wantSystemStubs := "--system-stub-classpath=" + generateSdkDexPath(tc.systemStub, tc.unbundledBuild)
- if !strings.Contains(hiddenapiRule.RuleParams.Command, wantSystemStubs) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantSystemStubs, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantSystemStubs)
wantTestStubs := "--test-stub-classpath=" + generateSdkDexPath(tc.testStub, tc.unbundledBuild)
- if !strings.Contains(hiddenapiRule.RuleParams.Command, wantTestStubs) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantTestStubs, hiddenapiRule.RuleParams.Command)
- }
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantTestStubs)
- wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(tc.corePlatformStub)
- if !strings.Contains(hiddenapiRule.RuleParams.Command, wantCorePlatformStubs) {
- t.Errorf("Expected %s in hiddenapi command, but it was not present: %s", wantCorePlatformStubs, hiddenapiRule.RuleParams.Command)
- }
+ wantCorePlatformStubs := "--core-platform-stub-classpath=" + generateDexPath(defaultJavaDir, tc.corePlatformStub)
+ android.AssertStringDoesContain(t, "hiddenapi command", hiddenapiRule.RuleParams.Command, wantCorePlatformStubs)
})
}
}
@@ -282,15 +263,15 @@
return fmt.Sprintf("%s/.intermediates/%s/android_common/%s/%s.jar", buildDir, subDir, dex, module)
}
-func generateDexPath(module string) string {
- return generateDexedPath(module, "dex", module)
+func generateDexPath(moduleDir string, module string) string {
+ return generateDexedPath(filepath.Join(moduleDir, module), "dex", module)
}
func generateSdkDexPath(module string, unbundled bool) string {
if unbundled {
return generateDexedPath("prebuilts/sdk/"+module, "dex", module)
}
- return generateDexPath(module)
+ return generateDexPath(defaultJavaDir, module)
}
func TestHiddenAPISingletonWithPrebuiltCsvFile(t *testing.T) {
@@ -304,36 +285,33 @@
// Where to find the prebuilt hiddenapi files:
prebuiltHiddenApiDir := "path/to/prebuilt/hiddenapi"
- ctx, _ := testHiddenAPIBootJars(t, `
+ result := hiddenApiFixtureFactory.Extend(
+ fixtureSetBootJarsProductVariable("platform:foo"),
+ fixtureSetPrebuiltHiddenApiDirProductVariable(&prebuiltHiddenApiDir),
+ ).RunTestWithBp(t, `
java_import {
name: "foo",
jars: ["a.jar"],
compile_dex: true,
}
- `, []string{"platform:foo"}, &prebuiltHiddenApiDir)
+ `)
expectedCpInput := prebuiltHiddenApiDir + "/hiddenapi-flags.csv"
expectedCpOutput := buildDir + "/hiddenapi/hiddenapi-flags.csv"
expectedFlagsCsv := buildDir + "/hiddenapi/hiddenapi-flags.csv"
- foo := ctx.ModuleForTests("foo", "android_common")
+ foo := result.ModuleForTests("foo", "android_common")
- hiddenAPI := ctx.SingletonForTests("hiddenapi")
+ hiddenAPI := result.SingletonForTests("hiddenapi")
cpRule := hiddenAPI.Rule("Cp")
actualCpInput := cpRule.BuildParams.Input
actualCpOutput := cpRule.BuildParams.Output
encodeDexRule := foo.Rule("hiddenAPIEncodeDex")
actualFlagsCsv := encodeDexRule.BuildParams.Args["flagsCsv"]
- if actualCpInput.String() != expectedCpInput {
- t.Errorf("Prebuilt hiddenapi cp rule input mismatch, actual: %s, expected: %s", actualCpInput, expectedCpInput)
- }
+ android.AssertStringEquals(t, "hiddenapi cp rule input", expectedCpInput, actualCpInput.String())
- if actualCpOutput.String() != expectedCpOutput {
- t.Errorf("Prebuilt hiddenapi cp rule output mismatch, actual: %s, expected: %s", actualCpOutput, expectedCpOutput)
- }
+ android.AssertStringEquals(t, "hiddenapi cp rule output", expectedCpOutput, actualCpOutput.String())
- if actualFlagsCsv != expectedFlagsCsv {
- t.Errorf("Prebuilt hiddenapi encode dex rule flags csv mismatch, actual: %s, expected: %s", actualFlagsCsv, expectedFlagsCsv)
- }
+ android.AssertStringEquals(t, "hiddenapi encode dex rule flags csv", expectedFlagsCsv, actualFlagsCsv)
}
diff --git a/java/java.go b/java/java.go
index 9e35835..6982f52 100644
--- a/java/java.go
+++ b/java/java.go
@@ -37,6 +37,36 @@
func init() {
RegisterJavaBuildComponents(android.InitRegistrationContext)
+ RegisterJavaSdkMemberTypes()
+}
+
+func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterModuleType("java_defaults", DefaultsFactory)
+
+ ctx.RegisterModuleType("java_library", LibraryFactory)
+ ctx.RegisterModuleType("java_library_static", LibraryStaticFactory)
+ ctx.RegisterModuleType("java_library_host", LibraryHostFactory)
+ ctx.RegisterModuleType("java_binary", BinaryFactory)
+ ctx.RegisterModuleType("java_binary_host", BinaryHostFactory)
+ ctx.RegisterModuleType("java_test", TestFactory)
+ ctx.RegisterModuleType("java_test_helper_library", TestHelperLibraryFactory)
+ ctx.RegisterModuleType("java_test_host", TestHostFactory)
+ ctx.RegisterModuleType("java_test_import", JavaTestImportFactory)
+ ctx.RegisterModuleType("java_import", ImportFactory)
+ ctx.RegisterModuleType("java_import_host", ImportFactoryHost)
+ ctx.RegisterModuleType("java_device_for_host", DeviceForHostFactory)
+ ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
+ ctx.RegisterModuleType("dex_import", DexImportFactory)
+
+ ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
+ ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
+ })
+
+ ctx.RegisterSingletonType("logtags", LogtagsSingleton)
+ ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
+}
+
+func RegisterJavaSdkMemberTypes() {
// Register sdk member types.
android.RegisterSdkMemberType(javaHeaderLibsSdkMemberType)
@@ -89,76 +119,7 @@
PropertyName: "java_tests",
},
})
-}
-func RegisterJavaBuildComponents(ctx android.RegistrationContext) {
- ctx.RegisterModuleType("java_defaults", DefaultsFactory)
-
- ctx.RegisterModuleType("java_library", LibraryFactory)
- ctx.RegisterModuleType("java_library_static", LibraryStaticFactory)
- ctx.RegisterModuleType("java_library_host", LibraryHostFactory)
- ctx.RegisterModuleType("java_binary", BinaryFactory)
- ctx.RegisterModuleType("java_binary_host", BinaryHostFactory)
- ctx.RegisterModuleType("java_test", TestFactory)
- ctx.RegisterModuleType("java_test_helper_library", TestHelperLibraryFactory)
- ctx.RegisterModuleType("java_test_host", TestHostFactory)
- ctx.RegisterModuleType("java_test_import", JavaTestImportFactory)
- ctx.RegisterModuleType("java_import", ImportFactory)
- ctx.RegisterModuleType("java_import_host", ImportFactoryHost)
- ctx.RegisterModuleType("java_device_for_host", DeviceForHostFactory)
- ctx.RegisterModuleType("java_host_for_device", HostForDeviceFactory)
- ctx.RegisterModuleType("dex_import", DexImportFactory)
-
- ctx.FinalDepsMutators(func(ctx android.RegisterMutatorsContext) {
- ctx.BottomUp("dexpreopt_tool_deps", dexpreoptToolDepsMutator).Parallel()
- })
-
- ctx.RegisterSingletonType("logtags", LogtagsSingleton)
- ctx.RegisterSingletonType("kythe_java_extract", kytheExtractJavaFactory)
-}
-
-func (j *Module) CheckStableSdkVersion() error {
- sdkVersion := j.sdkVersion()
- if sdkVersion.stable() {
- return nil
- }
- return fmt.Errorf("non stable SDK %v", sdkVersion)
-}
-
-func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
- if j.RequiresStableAPIs(ctx) {
- if sc, ok := ctx.Module().(sdkContext); ok {
- if !sc.sdkVersion().specified() {
- ctx.PropertyErrorf("sdk_version",
- "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
- }
- }
- }
-
- ctx.VisitDirectDeps(func(module android.Module) {
- tag := ctx.OtherModuleDependencyTag(module)
- switch module.(type) {
- // TODO(satayev): cover other types as well, e.g. imports
- case *Library, *AndroidLibrary:
- switch tag {
- case bootClasspathTag, libTag, staticLibTag, java9LibTag:
- checkLinkType(ctx, j, module.(linkTypeContext), tag.(dependencyTag))
- }
- }
- })
-}
-
-func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
- if sc, ok := ctx.Module().(sdkContext); ok {
- usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
- sdkVersionSpecified := sc.sdkVersion().specified()
- if usePlatformAPI && sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
- } else if !usePlatformAPI && !sdkVersionSpecified {
- ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
- }
-
- }
}
// TODO:
@@ -170,7 +131,8 @@
// DroidDoc
// Findbugs
-type CompilerProperties struct {
+// Properties that are common to most Java modules, i.e. whether it's a host or device module.
+type CommonProperties struct {
// list of source files used to compile the Java module. May be .java, .kt, .logtags, .proto,
// or .aidl files.
Srcs []string `android:"path,arch_variant"`
@@ -303,7 +265,9 @@
Hiddenapi_additional_annotations []string
}
-type CompilerDeviceProperties struct {
+// Properties that are specific to device modules. Host module factories should not add these when
+// constructing a new module.
+type DeviceProperties struct {
// if not blank, set to the version of the sdk to compile against.
// Defaults to compiling against the current platform.
Sdk_version *string
@@ -412,9 +376,9 @@
// Functionality common to Module and Import.
embeddableInModuleAndImport
- properties CompilerProperties
+ properties CommonProperties
protoProperties android.ProtoProperties
- deviceProperties CompilerDeviceProperties
+ deviceProperties DeviceProperties
// jar file containing header classes including static library dependencies, suitable for
// inserting into the bootclasspath/classpath of another compile
@@ -499,6 +463,62 @@
hideApexVariantFromMake bool
}
+func (j *Module) CheckStableSdkVersion() error {
+ sdkVersion := j.sdkVersion()
+ if sdkVersion.stable() {
+ return nil
+ }
+ if sdkVersion.kind == sdkCorePlatform {
+ if useLegacyCorePlatformApiByName(j.BaseModuleName()) {
+ return fmt.Errorf("non stable SDK %v - uses legacy core platform", sdkVersion)
+ } else {
+ // Treat stable core platform as stable.
+ return nil
+ }
+ } else {
+ return fmt.Errorf("non stable SDK %v", sdkVersion)
+ }
+}
+
+// checkSdkVersions enforces restrictions around SDK dependencies.
+func (j *Module) checkSdkVersions(ctx android.ModuleContext) {
+ if j.RequiresStableAPIs(ctx) {
+ if sc, ok := ctx.Module().(sdkContext); ok {
+ if !sc.sdkVersion().specified() {
+ ctx.PropertyErrorf("sdk_version",
+ "sdk_version must have a value when the module is located at vendor or product(only if PRODUCT_ENFORCE_PRODUCT_PARTITION_INTERFACE is set).")
+ }
+ }
+ }
+
+ // Make sure this module doesn't statically link to modules with lower-ranked SDK link type.
+ // See rank() for details.
+ ctx.VisitDirectDeps(func(module android.Module) {
+ tag := ctx.OtherModuleDependencyTag(module)
+ switch module.(type) {
+ // TODO(satayev): cover other types as well, e.g. imports
+ case *Library, *AndroidLibrary:
+ switch tag {
+ case bootClasspathTag, libTag, staticLibTag, java9LibTag:
+ j.checkSdkLinkType(ctx, module.(moduleWithSdkDep), tag.(dependencyTag))
+ }
+ }
+ })
+}
+
+func (j *Module) checkPlatformAPI(ctx android.ModuleContext) {
+ if sc, ok := ctx.Module().(sdkContext); ok {
+ usePlatformAPI := proptools.Bool(j.deviceProperties.Platform_apis)
+ sdkVersionSpecified := sc.sdkVersion().specified()
+ if usePlatformAPI && sdkVersionSpecified {
+ ctx.PropertyErrorf("platform_apis", "platform_apis must be false when sdk_version is not empty.")
+ } else if !usePlatformAPI && !sdkVersionSpecified {
+ ctx.PropertyErrorf("platform_apis", "platform_apis must be true when sdk_version is empty.")
+ }
+
+ }
+}
+
func (j *Module) addHostProperties() {
j.AddProperties(
&j.properties,
@@ -999,13 +1019,13 @@
}
}
-type linkType int
+type sdkLinkType int
const (
// TODO(jiyong) rename these for better readability. Make the allowed
// and disallowed link types explicit
// order is important here. See rank()
- javaCore linkType = iota
+ javaCore sdkLinkType = iota
javaSdk
javaSystem
javaModule
@@ -1013,7 +1033,7 @@
javaPlatform
)
-func (lt linkType) String() string {
+func (lt sdkLinkType) String() string {
switch lt {
case javaCore:
return "core Java API"
@@ -1032,18 +1052,19 @@
}
}
-// rank determins the total order among linkTypes. A link type of rank A can link to another link
-// type of rank B only when B <= A
-func (lt linkType) rank() int {
+// rank determines the total order among sdkLinkType. An SDK link type of rank A can link to
+// another SDK link type of rank B only when B <= A. For example, a module linking to Android SDK
+// can't statically depend on modules that use Platform API.
+func (lt sdkLinkType) rank() int {
return int(lt)
}
-type linkTypeContext interface {
+type moduleWithSdkDep interface {
android.Module
- getLinkType(name string) (ret linkType, stubs bool)
+ getSdkLinkType(name string) (ret sdkLinkType, stubs bool)
}
-func (m *Module) getLinkType(name string) (ret linkType, stubs bool) {
+func (m *Module) getSdkLinkType(name string) (ret sdkLinkType, stubs bool) {
switch name {
case "core.current.stubs", "legacy.core.platform.api.stubs", "stable.core.platform.api.stubs",
"stub-annotations", "private-stub-annotations-jar",
@@ -1087,23 +1108,26 @@
return javaSdk, false
}
-func checkLinkType(ctx android.ModuleContext, from *Module, to linkTypeContext, tag dependencyTag) {
+// checkSdkLinkType make sures the given dependency doesn't have a lower SDK link type rank than
+// this module's. See the comment on rank() for details and an example.
+func (j *Module) checkSdkLinkType(
+ ctx android.ModuleContext, dep moduleWithSdkDep, tag dependencyTag) {
if ctx.Host() {
return
}
- myLinkType, stubs := from.getLinkType(ctx.ModuleName())
+ myLinkType, stubs := j.getSdkLinkType(ctx.ModuleName())
if stubs {
return
}
- otherLinkType, _ := to.getLinkType(ctx.OtherModuleName(to))
+ depLinkType, _ := dep.getSdkLinkType(ctx.OtherModuleName(dep))
- if myLinkType.rank() < otherLinkType.rank() {
+ if myLinkType.rank() < depLinkType.rank() {
ctx.ModuleErrorf("compiles against %v, but dependency %q is compiling against %v. "+
"In order to fix this, consider adjusting sdk_version: OR platform_apis: "+
"property of the source or target module so that target module is built "+
"with the same or smaller API set when compared to the source.",
- myLinkType, ctx.OtherModuleName(to), otherLinkType)
+ myLinkType, ctx.OtherModuleName(dep), depLinkType)
}
}
@@ -1124,7 +1148,7 @@
}
}
- linkType, _ := j.getLinkType(ctx.ModuleName())
+ sdkLinkType, _ := j.getSdkLinkType(ctx.ModuleName())
ctx.VisitDirectDeps(func(module android.Module) {
otherName := ctx.OtherModuleName(module)
@@ -1148,7 +1172,7 @@
}
} else if ctx.OtherModuleHasProvider(module, JavaInfoProvider) {
dep := ctx.OtherModuleProvider(module, JavaInfoProvider).(JavaInfo)
- if linkType != javaPlatform &&
+ if sdkLinkType != javaPlatform &&
ctx.OtherModuleHasProvider(module, SyspropPublicStubInfoProvider) {
// dep is a sysprop implementation library, but this module is not linking against
// the platform, so it gets the sysprop public stubs library instead. Replace
@@ -2499,7 +2523,7 @@
func (j *Test) GenerateAndroidBuildActions(ctx android.ModuleContext) {
if j.testProperties.Test_options.Unit_test == nil && ctx.Host() {
// TODO(b/): Clean temporary heuristic to avoid unexpected onboarding.
- defaultUnitTest := !inList("tradefed", j.properties.Static_libs) && !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites) && !inList("robolectric-host-android_all", j.properties.Static_libs) && !inList("robolectric-host-android_all", j.properties.Libs)
+ defaultUnitTest := !inList("tradefed", j.properties.Static_libs) && !inList("tradefed", j.properties.Libs) && !inList("cts", j.testProperties.Test_suites)
j.testProperties.Test_options.Unit_test = proptools.BoolPtr(defaultUnitTest)
}
j.testConfig = tradefed.AutoGenJavaTestConfig(ctx, j.testProperties.Test_config, j.testProperties.Test_config_template,
@@ -3319,16 +3343,12 @@
// ],
// javacflags: ["-Xlint:all"],
// }
-func defaultsFactory() android.Module {
- return DefaultsFactory()
-}
-
func DefaultsFactory() android.Module {
module := &Defaults{}
module.AddProperties(
- &CompilerProperties{},
- &CompilerDeviceProperties{},
+ &CommonProperties{},
+ &DeviceProperties{},
&DexProperties{},
&DexpreoptProperties{},
&android.ProtoProperties{},
diff --git a/java/java_test.go b/java/java_test.go
index 670eefc..1c2ed2e 100644
--- a/java/java_test.go
+++ b/java/java_test.go
@@ -65,6 +65,7 @@
ctx.RegisterPreSingletonType("sdk_versions", sdkPreSingletonFactory)
}),
javaMockFS().AddToFixture(),
+ PrepareForTestWithJavaSdkLibraryFiles,
dexpreopt.PrepareForTestWithDexpreopt,
)
@@ -147,7 +148,11 @@
// deprecated
func testJavaError(t *testing.T, pattern string, bp string) (*android.TestContext, android.Config) {
t.Helper()
- return testJavaErrorWithConfig(t, pattern, testConfig(nil, bp, nil))
+ result := javaFixtureFactory.
+ Extend(dexpreopt.PrepareForTestWithDexpreopt).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
+ RunTestWithBp(t, bp)
+ return result.TestContext, result.Config
}
// testJavaErrorWithConfig is a legacy way of running tests of java modules that expect errors.
@@ -364,13 +369,9 @@
barTurbine := filepath.Join(buildDir, ".intermediates", "bar", "android_common", "turbine-combined", "bar.jar")
bazTurbine := filepath.Join(buildDir, ".intermediates", "baz", "android_common", "turbine-combined", "baz.jar")
- if !strings.Contains(javac.Args["classpath"], barTurbine) {
- t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], barTurbine)
- }
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], barTurbine)
- if !strings.Contains(javac.Args["classpath"], bazTurbine) {
- t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], bazTurbine)
- }
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], bazTurbine)
if len(combineJar.Inputs) != 2 || combineJar.Inputs[1].String() != baz {
t.Errorf("foo combineJar inputs %v does not contain %q", combineJar.Inputs, baz)
@@ -740,7 +741,7 @@
}
func TestJavaSdkLibraryImport(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.RunTestWithBp(t, `
java_library {
name: "foo",
srcs: ["a.java"],
@@ -778,16 +779,14 @@
`)
for _, scope := range []string{"", ".system", ".test"} {
- fooModule := ctx.ModuleForTests("foo"+scope, "android_common")
+ fooModule := result.ModuleForTests("foo"+scope, "android_common")
javac := fooModule.Rule("javac")
- sdklibStubsJar := ctx.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
- if !strings.Contains(javac.Args["classpath"], sdklibStubsJar.String()) {
- t.Errorf("foo classpath %v does not contain %q", javac.Args["classpath"], sdklibStubsJar.String())
- }
+ sdklibStubsJar := result.ModuleForTests("sdklib.stubs"+scope, "android_common").Rule("combineJar").Output
+ android.AssertStringDoesContain(t, "foo classpath", javac.Args["classpath"], sdklibStubsJar.String())
}
- CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`prebuilt_sdklib.stubs`,
`prebuilt_sdklib.stubs.source.test`,
`prebuilt_sdklib.stubs.system`,
@@ -796,7 +795,10 @@
}
func TestJavaSdkLibraryImport_WithSource(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "sdklib",
srcs: ["a.java"],
@@ -815,7 +817,7 @@
}
`)
- CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
`sdklib.impl`,
@@ -824,7 +826,7 @@
`sdklib.xml`,
})
- CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
// This should be prebuilt_sdklib.stubs but is set to sdklib.stubs because the
@@ -835,7 +837,10 @@
}
func TestJavaSdkLibraryImport_Preferred(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "sdklib",
srcs: ["a.java"],
@@ -855,7 +860,7 @@
}
`)
- CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
`prebuilt_sdklib`,
`sdklib.impl`,
@@ -864,7 +869,7 @@
`sdklib.xml`,
})
- CheckModuleDependencies(t, ctx, "prebuilt_sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "prebuilt_sdklib", "android_common", []string{
`prebuilt_sdklib.stubs`,
`sdklib.impl`,
`sdklib.xml`,
@@ -895,7 +900,7 @@
allowList []string
}
- createTestConfig := func(info testConfigInfo) android.Config {
+ createPreparer := func(info testConfigInfo) android.FixturePreparer {
bpFileTemplate := `
java_library {
name: "foo",
@@ -918,58 +923,70 @@
info.libraryType,
partitionToBpOption(info.toPartition))
- config := testConfig(nil, bpFile, nil)
- configVariables := config.TestProductVariables
+ return android.GroupFixturePreparers(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("bar"),
+ android.FixtureWithRootAndroidBp(bpFile),
+ android.FixtureModifyProductVariables(func(variables android.FixtureProductVariables) {
+ variables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
+ if info.enforceVendorInterface {
+ variables.DeviceVndkVersion = proptools.StringPtr("current")
+ }
+ variables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
+ variables.InterPartitionJavaLibraryAllowList = info.allowList
+ }),
+ )
+ }
- configVariables.EnforceProductPartitionInterface = proptools.BoolPtr(info.enforceProductInterface)
- if info.enforceVendorInterface {
- configVariables.DeviceVndkVersion = proptools.StringPtr("current")
- }
- configVariables.EnforceInterPartitionJavaSdkLibrary = proptools.BoolPtr(info.enforceJavaSdkLibraryCheck)
- configVariables.InterPartitionJavaLibraryAllowList = info.allowList
-
- return config
+ runTest := func(t *testing.T, info testConfigInfo, expectedErrorPattern string) {
+ t.Run(fmt.Sprintf("%#v", info), func(t *testing.T) {
+ errorHandler := android.FixtureExpectsNoErrors
+ if expectedErrorPattern != "" {
+ errorHandler = android.FixtureExpectsAtLeastOneErrorMatchingPattern(expectedErrorPattern)
+ }
+ javaFixtureFactory.ExtendWithErrorHandler(errorHandler).RunTest(t, createPreparer(info))
+ })
}
errorMessage := "is not allowed across the partitions"
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "product",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: false,
- }))
+ }, "")
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "product",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: false,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, "")
- testJavaErrorWithConfig(t, errorMessage, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "product",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, errorMessage)
- testJavaErrorWithConfig(t, errorMessage, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "vendor",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, errorMessage)
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "vendor",
toPartition: "system",
@@ -977,43 +994,43 @@
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
allowList: []string{"bar"},
- }))
+ }, "")
- testJavaErrorWithConfig(t, errorMessage, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_library",
fromPartition: "vendor",
toPartition: "product",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, errorMessage)
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_sdk_library",
fromPartition: "product",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, "")
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_sdk_library",
fromPartition: "vendor",
toPartition: "system",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, "")
- testJavaWithConfig(t, createTestConfig(testConfigInfo{
+ runTest(t, testConfigInfo{
libraryType: "java_sdk_library",
fromPartition: "vendor",
toPartition: "product",
enforceVendorInterface: true,
enforceProductInterface: true,
enforceJavaSdkLibraryCheck: true,
- }))
+ }, "")
}
func TestDefaults(t *testing.T) {
@@ -1829,7 +1846,14 @@
}
func TestJavaSdkLibrary(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithPrebuiltApis(map[string][]string{
+ "28": {"foo"},
+ "29": {"foo"},
+ "30": {"bar", "barney", "baz", "betty", "foo", "fred", "quuz", "wilma"},
+ }),
+ ).RunTestWithBp(t, `
droiddoc_exported_dir {
name: "droiddoc-templates-sdk",
path: ".",
@@ -1906,68 +1930,51 @@
`)
// check the existence of the internal modules
- ctx.ModuleForTests("foo", "android_common")
- ctx.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
- ctx.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
- ctx.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
- ctx.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
- ctx.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
- ctx.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
- ctx.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
- ctx.ModuleForTests("foo.api.public.28", "")
- ctx.ModuleForTests("foo.api.system.28", "")
- ctx.ModuleForTests("foo.api.test.28", "")
+ result.ModuleForTests("foo", "android_common")
+ result.ModuleForTests(apiScopePublic.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeSystem.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeTest.stubsLibraryModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopePublic.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeSystem.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests(apiScopeTest.stubsSourceModuleName("foo"), "android_common")
+ result.ModuleForTests("foo"+sdkXmlFileSuffix, "android_common")
+ result.ModuleForTests("foo.api.public.28", "")
+ result.ModuleForTests("foo.api.system.28", "")
+ result.ModuleForTests("foo.api.test.28", "")
- bazJavac := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+ bazJavac := result.ModuleForTests("baz", "android_common").Rule("javac")
// tests if baz is actually linked to the stubs lib
- if !strings.Contains(bazJavac.Args["classpath"], "foo.stubs.system.jar") {
- t.Errorf("baz javac classpath %v does not contain %q", bazJavac.Args["classpath"],
- "foo.stubs.system.jar")
- }
+ android.AssertStringDoesContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.system.jar")
// ... and not to the impl lib
- if strings.Contains(bazJavac.Args["classpath"], "foo.jar") {
- t.Errorf("baz javac classpath %v should not contain %q", bazJavac.Args["classpath"],
- "foo.jar")
- }
+ android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.jar")
// test if baz is not linked to the system variant of foo
- if strings.Contains(bazJavac.Args["classpath"], "foo.stubs.jar") {
- t.Errorf("baz javac classpath %v should not contain %q", bazJavac.Args["classpath"],
- "foo.stubs.jar")
- }
+ android.AssertStringDoesNotContain(t, "baz javac classpath", bazJavac.Args["classpath"], "foo.stubs.jar")
- bazTestJavac := ctx.ModuleForTests("baz-test", "android_common").Rule("javac")
+ bazTestJavac := result.ModuleForTests("baz-test", "android_common").Rule("javac")
// tests if baz-test is actually linked to the test stubs lib
- if !strings.Contains(bazTestJavac.Args["classpath"], "foo.stubs.test.jar") {
- t.Errorf("baz-test javac classpath %v does not contain %q", bazTestJavac.Args["classpath"],
- "foo.stubs.test.jar")
- }
+ android.AssertStringDoesContain(t, "baz-test javac classpath", bazTestJavac.Args["classpath"], "foo.stubs.test.jar")
- baz29Javac := ctx.ModuleForTests("baz-29", "android_common").Rule("javac")
+ baz29Javac := result.ModuleForTests("baz-29", "android_common").Rule("javac")
// tests if baz-29 is actually linked to the system 29 stubs lib
- if !strings.Contains(baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar") {
- t.Errorf("baz-29 javac classpath %v does not contain %q", baz29Javac.Args["classpath"],
- "prebuilts/sdk/29/system/foo.jar")
- }
+ android.AssertStringDoesContain(t, "baz-29 javac classpath", baz29Javac.Args["classpath"], "prebuilts/sdk/29/system/foo.jar")
- bazModule30Javac := ctx.ModuleForTests("baz-module-30", "android_common").Rule("javac")
+ bazModule30Javac := result.ModuleForTests("baz-module-30", "android_common").Rule("javac")
// tests if "baz-module-30" is actually linked to the module 30 stubs lib
- if !strings.Contains(bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar") {
- t.Errorf("baz-module-30 javac classpath %v does not contain %q", bazModule30Javac.Args["classpath"],
- "prebuilts/sdk/30/module-lib/foo.jar")
- }
+ android.AssertStringDoesContain(t, "baz-module-30 javac classpath", bazModule30Javac.Args["classpath"], "prebuilts/sdk/30/module-lib/foo.jar")
// test if baz has exported SDK lib names foo and bar to qux
- qux := ctx.ModuleForTests("qux", "android_common")
+ qux := result.ModuleForTests("qux", "android_common")
if quxLib, ok := qux.Module().(*Library); ok {
sdkLibs := quxLib.ClassLoaderContexts().UsesLibs()
- if w := []string{"foo", "bar", "fred", "quuz"}; !reflect.DeepEqual(w, sdkLibs) {
- t.Errorf("qux should export %q but exports %q", w, sdkLibs)
- }
+ android.AssertDeepEquals(t, "qux exports", []string{"foo", "bar", "fred", "quuz"}, sdkLibs)
}
}
func TestJavaSdkLibrary_StubOrImplOnlyLibs(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "sdklib",
srcs: ["a.java"],
@@ -1987,20 +1994,23 @@
`)
for _, implName := range []string{"sdklib", "sdklib.impl"} {
- implJavacCp := ctx.ModuleForTests(implName, "android_common").Rule("javac").Args["classpath"]
+ implJavacCp := result.ModuleForTests(implName, "android_common").Rule("javac").Args["classpath"]
if !strings.Contains(implJavacCp, "/foo.jar") || strings.Contains(implJavacCp, "/bar.jar") {
t.Errorf("%v javac classpath %v does not contain foo and not bar", implName, implJavacCp)
}
}
stubName := apiScopePublic.stubsLibraryModuleName("sdklib")
- stubsJavacCp := ctx.ModuleForTests(stubName, "android_common").Rule("javac").Args["classpath"]
+ stubsJavacCp := result.ModuleForTests(stubName, "android_common").Rule("javac").Args["classpath"]
if strings.Contains(stubsJavacCp, "/foo.jar") || !strings.Contains(stubsJavacCp, "/bar.jar") {
t.Errorf("stubs javac classpath %v does not contain bar and not foo", stubsJavacCp)
}
}
func TestJavaSdkLibrary_DoNotAccessImplWhenItIsNotBuilt(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java"],
@@ -2018,14 +2028,17 @@
`)
// The bar library should depend on the stubs jar.
- barLibrary := ctx.ModuleForTests("bar", "android_common").Rule("javac")
+ barLibrary := result.ModuleForTests("bar", "android_common").Rule("javac")
if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs\.jar$`, barLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
t.Errorf("expected %q, found %#q", expected, actual)
}
}
func TestJavaSdkLibrary_UseSourcesFromAnotherSdkLibrary(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java"],
@@ -2043,7 +2056,13 @@
}
func TestJavaSdkLibrary_AccessOutputFiles_MissingScope(t *testing.T) {
- testJavaError(t, `"foo" does not provide api scope system`, `
+ javaFixtureFactory.
+ Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`"foo" does not provide api scope system`)).
+ RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java"],
@@ -2061,7 +2080,10 @@
}
func TestJavaSdkLibrary_Deps(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("sdklib"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "sdklib",
srcs: ["a.java"],
@@ -2073,7 +2095,7 @@
}
`)
- CheckModuleDependencies(t, ctx, "sdklib", "android_common", []string{
+ CheckModuleDependencies(t, result.TestContext, "sdklib", "android_common", []string{
`dex2oatd`,
`sdklib.impl`,
`sdklib.stubs`,
@@ -2083,7 +2105,7 @@
}
func TestJavaSdkLibraryImport_AccessOutputFiles(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.RunTestWithBp(t, `
java_sdk_library_import {
name: "foo",
public: {
@@ -2116,63 +2138,74 @@
`
t.Run("stubs.source", func(t *testing.T) {
- testJavaError(t, `stubs.source not available for api scope public`, bp+`
- java_library {
- name: "bar",
- srcs: [":foo{.public.stubs.source}"],
- java_resources: [
- ":foo{.public.api.txt}",
- ":foo{.public.removed-api.txt}",
- ],
- }
- `)
+ javaFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`stubs.source not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: [":foo{.public.stubs.source}"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
})
t.Run("api.txt", func(t *testing.T) {
- testJavaError(t, `api.txt not available for api scope public`, bp+`
- java_library {
- name: "bar",
- srcs: ["a.java"],
- java_resources: [
- ":foo{.public.api.txt}",
- ],
- }
- `)
+ javaFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`api.txt not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.api.txt}",
+ ],
+ }
+ `)
})
t.Run("removed-api.txt", func(t *testing.T) {
- testJavaError(t, `removed-api.txt not available for api scope public`, bp+`
- java_library {
- name: "bar",
- srcs: ["a.java"],
- java_resources: [
- ":foo{.public.removed-api.txt}",
- ],
- }
- `)
+ javaFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`removed-api.txt not available for api scope public`)).
+ RunTestWithBp(t, bp+`
+ java_library {
+ name: "bar",
+ srcs: ["a.java"],
+ java_resources: [
+ ":foo{.public.removed-api.txt}",
+ ],
+ }
+ `)
})
}
func TestJavaSdkLibrary_InvalidScopes(t *testing.T) {
- testJavaError(t, `module "foo": enabled api scope "system" depends on disabled scope "public"`, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java", "b.java"],
- api_packages: ["foo"],
- // Explicitly disable public to test the check that ensures the set of enabled
- // scopes is consistent.
- public: {
- enabled: false,
- },
- system: {
- enabled: true,
- },
- }
+ javaFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`module "foo": enabled api scope "system" depends on disabled scope "public"`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java", "b.java"],
+ api_packages: ["foo"],
+ // Explicitly disable public to test the check that ensures the set of enabled
+ // scopes is consistent.
+ public: {
+ enabled: false,
+ },
+ system: {
+ enabled: true,
+ },
+ }
`)
}
func TestJavaSdkLibrary_SdkVersion_ForScope(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java", "b.java"],
@@ -2186,7 +2219,10 @@
}
func TestJavaSdkLibrary_ModuleLib(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java", "b.java"],
@@ -2202,7 +2238,10 @@
}
func TestJavaSdkLibrary_SystemServer(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java", "b.java"],
@@ -2218,26 +2257,31 @@
}
func TestJavaSdkLibrary_MissingScope(t *testing.T) {
- testJavaError(t, `requires api scope module-lib from foo but it only has \[\] available`, `
- java_sdk_library {
- name: "foo",
- srcs: ["a.java"],
- public: {
- enabled: false,
- },
- }
+ javaFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(`requires api scope module-lib from foo but it only has \[\] available`)).
+ RunTestWithBp(t, `
+ java_sdk_library {
+ name: "foo",
+ srcs: ["a.java"],
+ public: {
+ enabled: false,
+ },
+ }
- java_library {
- name: "baz",
- srcs: ["a.java"],
- libs: ["foo"],
- sdk_version: "module_current",
- }
+ java_library {
+ name: "baz",
+ srcs: ["a.java"],
+ libs: ["foo"],
+ sdk_version: "module_current",
+ }
`)
}
func TestJavaSdkLibrary_FallbackScope(t *testing.T) {
- testJava(t, `
+ javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java"],
@@ -2257,7 +2301,10 @@
}
func TestJavaSdkLibrary_DefaultToStubs(t *testing.T) {
- ctx, _ := testJava(t, `
+ result := javaFixtureFactory.Extend(
+ PrepareForTestWithJavaSdkLibraryFiles,
+ FixtureWithLastReleaseApis("foo"),
+ ).RunTestWithBp(t, `
java_sdk_library {
name: "foo",
srcs: ["a.java"],
@@ -2277,7 +2324,7 @@
}
`)
// The baz library should depend on the system stubs jar.
- bazLibrary := ctx.ModuleForTests("baz", "android_common").Rule("javac")
+ bazLibrary := result.ModuleForTests("baz", "android_common").Rule("javac")
if expected, actual := `^-classpath .*:/[^:]*/turbine-combined/foo\.stubs.system\.jar$`, bazLibrary.Args["classpath"]; !regexp.MustCompile(expected).MatchString(actual) {
t.Errorf("expected %q, found %#q", expected, actual)
}
diff --git a/java/legacy_core_platform_api_usage.go b/java/legacy_core_platform_api_usage.go
index c25bc4a..5949edd 100644
--- a/java/legacy_core_platform_api_usage.go
+++ b/java/legacy_core_platform_api_usage.go
@@ -109,7 +109,7 @@
"PrintSpooler",
"RollbackTest",
"service-blobstore",
- "service-connectivity",
+ "service-connectivity-pre-jarjar",
"service-jobscheduler",
"services",
"services.accessibility",
@@ -161,7 +161,11 @@
}
func useLegacyCorePlatformApi(ctx android.EarlyModuleContext) bool {
- _, found := legacyCorePlatformApiLookup[ctx.ModuleName()]
+ return useLegacyCorePlatformApiByName(ctx.ModuleName())
+}
+
+func useLegacyCorePlatformApiByName(name string) bool {
+ _, found := legacyCorePlatformApiLookup[name]
return found
}
diff --git a/java/lint.go b/java/lint.go
index 5940eac..9f677db 100644
--- a/java/lint.go
+++ b/java/lint.go
@@ -189,6 +189,10 @@
remoteRSPInputs android.Paths
}
+func lintRBEExecStrategy(ctx android.ModuleContext) string {
+ return ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.LocalExecStrategy)
+}
+
func (l *linter) writeLintProjectXML(ctx android.ModuleContext, rule *android.RuleBuilder) lintPaths {
var deps android.Paths
var remoteInputs android.Paths
@@ -280,7 +284,8 @@
cmd.FlagForEachArg("--extra_checks_jar ", l.extraLintCheckJars.Strings())
trackInputDependency(l.extraLintCheckJars...)
- if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") {
+ if ctx.Config().UseRBE() && ctx.Config().IsEnvTrue("RBE_LINT") &&
+ lintRBEExecStrategy(ctx) != remoteexec.LocalExecStrategy {
// TODO(b/181912787): remove these and use "." instead.
cmd.FlagWithArg("--root_dir ", "/b/f/w")
} else {
@@ -391,7 +396,7 @@
pool := ctx.Config().GetenvWithDefault("RBE_LINT_POOL", "java16")
// TODO(b/181912787): this should be local fallback once the hack that passes /b/f/w in project.xml
// is removed.
- execStrategy := ctx.Config().GetenvWithDefault("RBE_LINT_EXEC_STRATEGY", remoteexec.RemoteExecStrategy)
+ execStrategy := lintRBEExecStrategy(ctx)
labels := map[string]string{"type": "tool", "name": "lint"}
rule.Remoteable(android.RemoteRuleSupports{RBE: true})
remoteInputs := lintPaths.remoteInputs
@@ -417,6 +422,7 @@
"ANDROID_SDK_HOME",
"SDK_ANNOTATIONS",
"LINT_OPTS",
+ "LANG",
},
Platform: map[string]string{remoteexec.PoolKey: pool},
}).NoVarTemplate(ctx.Config()))
diff --git a/java/platform_compat_config.go b/java/platform_compat_config.go
index 2c47b0a..4bfd4e2 100644
--- a/java/platform_compat_config.go
+++ b/java/platform_compat_config.go
@@ -20,11 +20,17 @@
)
func init() {
- android.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
- android.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
- android.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
+ registerPlatformCompatConfigBuildComponents(android.InitRegistrationContext)
}
+func registerPlatformCompatConfigBuildComponents(ctx android.RegistrationContext) {
+ ctx.RegisterSingletonType("platform_compat_config_singleton", platformCompatConfigSingletonFactory)
+ ctx.RegisterModuleType("platform_compat_config", PlatformCompatConfigFactory)
+ ctx.RegisterModuleType("global_compat_config", globalCompatConfigFactory)
+}
+
+var PrepareForTestWithPlatformCompatConfig = android.FixtureRegisterWithContext(registerPlatformCompatConfigBuildComponents)
+
func platformCompatConfigPath(ctx android.PathContext) android.OutputPath {
return android.PathForOutput(ctx, "compat_config", "merged_compat_config.xml")
}
@@ -146,7 +152,7 @@
func PlatformCompatConfigFactory() android.Module {
module := &platformCompatConfig{}
module.AddProperties(&module.properties)
- android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibFirst)
+ android.InitAndroidArchModule(module, android.DeviceSupported, android.MultilibCommon)
return module
}
diff --git a/java/proto.go b/java/proto.go
index 652a4da..8731822 100644
--- a/java/proto.go
+++ b/java/proto.go
@@ -94,7 +94,7 @@
}
}
-func protoFlags(ctx android.ModuleContext, j *CompilerProperties, p *android.ProtoProperties,
+func protoFlags(ctx android.ModuleContext, j *CommonProperties, p *android.ProtoProperties,
flags javaBuilderFlags) javaBuilderFlags {
flags.proto = android.GetProtoFlags(ctx, p)
diff --git a/java/sdk_library.go b/java/sdk_library.go
index b03f90c..e1ca77d 100644
--- a/java/sdk_library.go
+++ b/java/sdk_library.go
@@ -1681,7 +1681,7 @@
var _ sdkLibraryComponentNamingScheme = (*defaultNamingScheme)(nil)
-func moduleStubLinkType(name string) (stub bool, ret linkType) {
+func moduleStubLinkType(name string) (stub bool, ret sdkLinkType) {
// This suffix-based approach is fragile and could potentially mis-trigger.
// TODO(b/155164730): Clean this up when modules no longer reference sdk_lib stubs directly.
if strings.HasSuffix(name, ".stubs.public") || strings.HasSuffix(name, "-stubs-publicapi") {
diff --git a/java/system_modules_test.go b/java/system_modules_test.go
index 44049ee..3d9f398 100644
--- a/java/system_modules_test.go
+++ b/java/system_modules_test.go
@@ -20,7 +20,7 @@
"android/soong/android"
)
-func normalizedPathsToHeaderJars(result *android.TestResult, moduleNames ...string) []string {
+func getModuleHeaderJarsAsNormalizedPaths(result *android.TestResult, moduleNames ...string) []string {
paths := []string{}
for _, moduleName := range moduleNames {
module := result.Module(moduleName, "android_common")
@@ -57,8 +57,8 @@
sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs
// The expected paths are the header jars from the source input modules.
- expectedSourcePaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2")
- result.AssertArrayString("source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs))
+ expectedSourcePaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2")
+ android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs))
}
var addPrebuiltSystemModules = android.FixtureAddTextFile("prebuilts/Android.bp", `
@@ -84,8 +84,8 @@
prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs
// The expected paths are the header jars from the renamed prebuilt input modules.
- expectedPrebuiltPaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2")
- result.AssertArrayString("renamed prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs))
+ expectedPrebuiltPaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2")
+ android.AssertArrayString(t, "renamed prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs))
}
func TestJavaSystemModulesMixSourceAndPrebuilt(t *testing.T) {
@@ -99,14 +99,14 @@
sourceInputs := sourceSystemModules.Rule("jarsTosystemModules").Inputs
// The expected paths are the header jars from the source input modules.
- expectedSourcePaths := normalizedPathsToHeaderJars(result, "system-module1", "system-module2")
- result.AssertArrayString("source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs))
+ expectedSourcePaths := getModuleHeaderJarsAsNormalizedPaths(result, "system-module1", "system-module2")
+ android.AssertArrayString(t, "source system modules inputs", expectedSourcePaths, result.NormalizePathsForTesting(sourceInputs))
// check the existence of the renamed prebuilt module
prebuiltSystemModules := result.ModuleForTests("prebuilt_system-modules", "android_common")
prebuiltInputs := prebuiltSystemModules.Rule("jarsTosystemModules").Inputs
// The expected paths are the header jars from the renamed prebuilt input modules.
- expectedPrebuiltPaths := normalizedPathsToHeaderJars(result, "prebuilt_system-module1", "prebuilt_system-module2")
- result.AssertArrayString("prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs))
+ expectedPrebuiltPaths := getModuleHeaderJarsAsNormalizedPaths(result, "prebuilt_system-module1", "prebuilt_system-module2")
+ android.AssertArrayString(t, "prebuilt system modules inputs", expectedPrebuiltPaths, result.NormalizePathsForTesting(prebuiltInputs))
}
diff --git a/java/testing.go b/java/testing.go
index 4e1997e..896bcf8 100644
--- a/java/testing.go
+++ b/java/testing.go
@@ -61,27 +61,95 @@
PrepareForTestWithJavaDefaultModules,
)
+// Prepare a fixture with the standard files required by a java_sdk_library module.
+var PrepareForTestWithJavaSdkLibraryFiles = android.FixtureMergeMockFs(javaSdkLibraryFiles)
+
+var javaSdkLibraryFiles = android.MockFS{
+ "api/current.txt": nil,
+ "api/removed.txt": nil,
+ "api/system-current.txt": nil,
+ "api/system-removed.txt": nil,
+ "api/test-current.txt": nil,
+ "api/test-removed.txt": nil,
+ "api/module-lib-current.txt": nil,
+ "api/module-lib-removed.txt": nil,
+ "api/system-server-current.txt": nil,
+ "api/system-server-removed.txt": nil,
+}
+
+// FixtureWithLastReleaseApis creates a preparer that creates prebuilt versions of the specified
+// modules for the `last` API release. By `last` it just means last in the list of supplied versions
+// and as this only provides one version it can be any value.
+//
+// This uses FixtureWithPrebuiltApis under the covers so the limitations of that apply to this.
+func FixtureWithLastReleaseApis(moduleNames ...string) android.FixturePreparer {
+ return FixtureWithPrebuiltApis(map[string][]string{
+ "30": moduleNames,
+ })
+}
+
+// PrepareForTestWithPrebuiltsOfCurrentApi is a preparer that creates prebuilt versions of the
+// standard modules for the current version.
+//
+// This uses FixtureWithPrebuiltApis under the covers so the limitations of that apply to this.
+var PrepareForTestWithPrebuiltsOfCurrentApi = FixtureWithPrebuiltApis(map[string][]string{
+ "current": {},
+ // Can't have current on its own as it adds a prebuilt_apis module but doesn't add any
+ // .txt files which causes the prebuilt_apis module to fail.
+ "30": {},
+})
+
+// FixtureWithPrebuiltApis creates a preparer that will define prebuilt api modules for the
+// specified releases and modules.
+//
+// The supplied map keys are the releases, e.g. current, 29, 30, etc. The values are a list of
+// modules for that release. Due to limitations in the prebuilt_apis module which this preparer
+// uses the set of releases must include at least one numbered release, i.e. it cannot just include
+// "current".
+//
+// This defines a file in the mock file system in a predefined location (prebuilts/sdk/Android.bp)
+// and so only one instance of this can be used in each fixture.
+func FixtureWithPrebuiltApis(release2Modules map[string][]string) android.FixturePreparer {
+ mockFS := android.MockFS{}
+ path := "prebuilts/sdk/Android.bp"
+
+ bp := fmt.Sprintf(`
+ prebuilt_apis {
+ name: "sdk",
+ api_dirs: ["%s"],
+ imports_sdk_version: "none",
+ imports_compile_dex: true,
+ }
+ `, strings.Join(android.SortedStringKeys(release2Modules), `", "`))
+
+ for release, modules := range release2Modules {
+ libs := append([]string{"android", "core-for-system-modules"}, modules...)
+ mockFS.Merge(prebuiltApisFilesForLibs([]string{release}, libs))
+ }
+ return android.GroupFixturePreparers(
+ // A temporary measure to discard the definitions provided by default by javaMockFS() to allow
+ // the changes that use this preparer to fix tests to be separated from the change to remove
+ // javaMockFS().
+ android.FixtureModifyMockFS(func(fs android.MockFS) {
+ for k, _ := range fs {
+ if strings.HasPrefix(k, "prebuilts/sdk/") {
+ delete(fs, k)
+ }
+ }
+ }),
+ android.FixtureAddTextFile(path, bp),
+ android.FixtureMergeMockFs(mockFS),
+ )
+}
+
func javaMockFS() android.MockFS {
mockFS := android.MockFS{
- "api/current.txt": nil,
- "api/removed.txt": nil,
- "api/system-current.txt": nil,
- "api/system-removed.txt": nil,
- "api/test-current.txt": nil,
- "api/test-removed.txt": nil,
-
"prebuilts/sdk/tools/core-lambda-stubs.jar": nil,
"prebuilts/sdk/Android.bp": []byte(`prebuilt_apis { name: "sdk", api_dirs: ["14", "28", "30", "current"], imports_sdk_version: "none", imports_compile_dex:true,}`),
"bin.py": nil,
python.StubTemplateHost: []byte(`PYTHON_BINARY = '%interpreter%'
MAIN_FILE = '%main%'`),
-
- // For java_sdk_library
- "api/module-lib-current.txt": nil,
- "api/module-lib-removed.txt": nil,
- "api/system-server-current.txt": nil,
- "api/system-server-removed.txt": nil,
}
levels := []string{"14", "28", "29", "30", "current"}
@@ -101,6 +169,7 @@
bp += GatherRequiredDepsForTest()
mockFS := javaMockFS()
+ mockFS.Merge(javaSdkLibraryFiles)
cc.GatherRequiredFilesForTest(mockFS)
diff --git a/rust/builder.go b/rust/builder.go
index 6326124..9d462d4 100644
--- a/rust/builder.go
+++ b/rust/builder.go
@@ -194,8 +194,7 @@
}
if len(deps.SrcDeps) > 0 {
- genSubDir := "out/"
- moduleGenDir := android.PathForModuleOut(ctx, genSubDir)
+ moduleGenDir := ctx.RustModule().compiler.CargoOutDir()
var outputs android.WritablePaths
for _, genSrc := range deps.SrcDeps {
@@ -208,7 +207,7 @@
ctx.Build(pctx, android.BuildParams{
Rule: cp,
- Description: "cp " + moduleGenDir.Rel(),
+ Description: "cp " + moduleGenDir.Path().Rel(),
Outputs: outputs,
Inputs: deps.SrcDeps,
Args: map[string]string{
diff --git a/rust/compiler.go b/rust/compiler.go
index c26f208..98ad7ad 100644
--- a/rust/compiler.go
+++ b/rust/compiler.go
@@ -60,6 +60,7 @@
InstallInData = iota
incorrectSourcesError = "srcs can only contain one path for a rust file and source providers prefixed by \":\""
+ genSubDir = "out/"
)
type BaseCompilerProperties struct {
@@ -154,6 +155,10 @@
distFile android.OptionalPath
// Stripped output file. If Valid(), this file will be installed instead of outputFile.
strippedOutputFile android.OptionalPath
+
+ // If a crate has a source-generated dependency, a copy of the source file
+ // will be available in cargoOutDir (equivalent to Cargo OUT_DIR).
+ cargoOutDir android.ModuleOutPath
}
func (compiler *baseCompiler) Disabled() bool {
@@ -243,6 +248,14 @@
panic(fmt.Errorf("baseCrater doesn't know how to crate things!"))
}
+func (compiler *baseCompiler) initialize(ctx ModuleContext) {
+ compiler.cargoOutDir = android.PathForModuleOut(ctx, genSubDir)
+}
+
+func (compiler *baseCompiler) CargoOutDir() android.OptionalPath {
+ return android.OptionalPathForPath(compiler.cargoOutDir)
+}
+
func (compiler *baseCompiler) isDependencyRoot() bool {
return false
}
diff --git a/rust/project_json.go b/rust/project_json.go
index 32ce6f4..8d3d250 100644
--- a/rust/project_json.go
+++ b/rust/project_json.go
@@ -45,11 +45,12 @@
}
type rustProjectCrate struct {
- DisplayName string `json:"display_name"`
- RootModule string `json:"root_module"`
- Edition string `json:"edition,omitempty"`
- Deps []rustProjectDep `json:"deps"`
- Cfgs []string `json:"cfgs"`
+ DisplayName string `json:"display_name"`
+ RootModule string `json:"root_module"`
+ Edition string `json:"edition,omitempty"`
+ Deps []rustProjectDep `json:"deps"`
+ Cfgs []string `json:"cfgs"`
+ Env map[string]string `json:"env"`
}
type rustProjectJson struct {
@@ -136,7 +137,7 @@
}
})
if !foundSource {
- fmt.Errorf("No valid source for source provider found: %v\n", rModule)
+ ctx.Errorf("No valid source for source provider found: %v\n", rModule)
}
return sourceSrc, foundSource
}
@@ -220,7 +221,7 @@
func (singleton *projectGeneratorSingleton) addCrate(ctx android.SingletonContext, rModule *Module, comp *baseCompiler) (int, bool) {
rootModule, ok := crateSource(ctx, rModule, comp)
if !ok {
- fmt.Errorf("Unable to find source for valid module: %v", rModule)
+ ctx.Errorf("Unable to find source for valid module: %v", rModule)
return 0, false
}
@@ -230,6 +231,11 @@
Edition: comp.edition(),
Deps: make([]rustProjectDep, 0),
Cfgs: make([]string, 0),
+ Env: make(map[string]string),
+ }
+
+ if comp.CargoOutDir().Valid() {
+ crate.Env["OUT_DIR"] = comp.CargoOutDir().String()
}
deps := make(map[string]int)
diff --git a/rust/project_json_test.go b/rust/project_json_test.go
index ba66215..289bcb8 100644
--- a/rust/project_json_test.go
+++ b/rust/project_json_test.go
@@ -190,8 +190,8 @@
}
}
}
- // Check that liba depends on libbindings1
if strings.Contains(rootModule, "d/src/lib.rs") {
+ // Check that libd depends on libbindings1
found := false
for _, depName := range validateDependencies(t, crate) {
if depName == "bindings1" {
@@ -200,8 +200,17 @@
}
}
if !found {
- t.Errorf("liba does not depend on libbindings1: %v", crate)
+ t.Errorf("libd does not depend on libbindings1: %v", crate)
}
+ // Check that OUT_DIR is populated.
+ env, ok := crate["env"].(map[string]interface{})
+ if !ok {
+ t.Errorf("libd does not have its environment variables set: %v", crate)
+ }
+ if _, ok = env["OUT_DIR"]; !ok {
+ t.Errorf("libd does not have its OUT_DIR set: %v", env)
+ }
+
}
}
}
diff --git a/rust/rust.go b/rust/rust.go
index dc23abb..8ebdb72 100644
--- a/rust/rust.go
+++ b/rust/rust.go
@@ -320,12 +320,16 @@
}
type compiler interface {
+ initialize(ctx ModuleContext)
compilerFlags(ctx ModuleContext, flags Flags) Flags
compilerProps() []interface{}
compile(ctx ModuleContext, flags Flags, deps PathDeps) android.Path
compilerDeps(ctx DepsContext, deps Deps) Deps
crateName() string
+ // Output directory in which source-generated code from dependencies is
+ // copied. This is equivalent to Cargo's OUT_DIR variable.
+ CargoOutDir() android.OptionalPath
inData() bool
install(ctx ModuleContext)
relativeInstallPath() string
@@ -711,6 +715,7 @@
}
if mod.compiler != nil && !mod.compiler.Disabled() {
+ mod.compiler.initialize(ctx)
outputFile := mod.compiler.compile(ctx, flags, deps)
mod.outputFile = android.OptionalPathForPath(outputFile)
diff --git a/scripts/manifest_check.py b/scripts/manifest_check.py
index 0eb1b76..973a675 100755
--- a/scripts/manifest_check.py
+++ b/scripts/manifest_check.py
@@ -19,6 +19,8 @@
from __future__ import print_function
import argparse
+import re
+import subprocess
import sys
from xml.dom import minidom
@@ -59,64 +61,44 @@
dest='extract_target_sdk_version',
action='store_true',
help='print the targetSdkVersion from the manifest')
+ parser.add_argument('--aapt',
+ dest='aapt',
+ help='path to aapt executable')
parser.add_argument('--output', '-o', dest='output', help='output AndroidManifest.xml file')
parser.add_argument('input', help='input AndroidManifest.xml file')
return parser.parse_args()
-def enforce_uses_libraries(doc, uses_libraries, optional_uses_libraries, relax):
- """Verify that the <uses-library> tags in the manifest match those provided by the build system.
+def enforce_uses_libraries(manifest, required, optional, relax, is_apk = False):
+ """Verify that the <uses-library> tags in the manifest match those provided
+ by the build system.
Args:
- doc: The XML document.
- uses_libraries: The names of <uses-library> tags known to the build system
- optional_uses_libraries: The names of <uses-library> tags with required:fals
- known to the build system
- Raises:
- RuntimeError: Invalid manifest
- ManifestMismatchError: Manifest does not match
+ manifest: manifest (either parsed XML or aapt dump of APK)
+ required: required libs known to the build system
+ optional: optional libs known to the build system
+ relax: if true, suppress error on mismatch and just write it to file
+ is_apk: if the manifest comes from an APK or an XML file
"""
+ if is_apk:
+ manifest_required, manifest_optional = extract_uses_libs_apk(manifest)
+ else:
+ manifest_required, manifest_optional = extract_uses_libs_xml(manifest)
- manifest = parse_manifest(doc)
- elems = get_children_with_tag(manifest, 'application')
- application = elems[0] if len(elems) == 1 else None
- if len(elems) > 1:
- raise RuntimeError('found multiple <application> tags')
- elif not elems:
- if uses_libraries or optional_uses_libraries:
- raise ManifestMismatchError('no <application> tag found')
- return
+ if required is None:
+ required = []
- return verify_uses_library(application, uses_libraries, optional_uses_libraries, relax)
-
-
-def verify_uses_library(application, uses_libraries, optional_uses_libraries, relax):
- """Verify that the uses-library values known to the build system match the manifest.
-
- Args:
- application: the <application> tag in the manifest.
- uses_libraries: the names of expected <uses-library> tags.
- optional_uses_libraries: the names of expected <uses-library> tags with required="false".
- Raises:
- ManifestMismatchError: Manifest does not match
- """
-
- if uses_libraries is None:
- uses_libraries = []
-
- if optional_uses_libraries is None:
- optional_uses_libraries = []
-
- manifest_uses_libraries, manifest_optional_uses_libraries = parse_uses_library(application)
+ if optional is None:
+ optional = []
err = []
- if manifest_uses_libraries != uses_libraries:
+ if manifest_required != required:
err.append('Expected required <uses-library> tags "%s", got "%s"' %
- (', '.join(uses_libraries), ', '.join(manifest_uses_libraries)))
+ (', '.join(required), ', '.join(manifest_required)))
- if manifest_optional_uses_libraries != optional_uses_libraries:
+ if manifest_optional != optional:
err.append('Expected optional <uses-library> tags "%s", got "%s"' %
- (', '.join(optional_uses_libraries), ', '.join(manifest_optional_uses_libraries)))
+ (', '.join(optional), ', '.join(manifest_optional)))
if err:
errmsg = '\n'.join(err)
@@ -126,19 +108,43 @@
return None
-def parse_uses_library(application):
- """Extract uses-library tags from the manifest.
- Args:
- application: the <application> tag in the manifest.
- """
+def extract_uses_libs_apk(badging):
+ """Extract <uses-library> tags from the manifest of an APK."""
+
+ pattern = re.compile("^uses-library(-not-required)?:'(.*)'$", re.MULTILINE)
+
+ required = []
+ optional = []
+ for match in re.finditer(pattern, badging):
+ libname = match.group(2)
+ if match.group(1) == None:
+ required.append(libname)
+ else:
+ optional.append(libname)
+
+ return first_unique_elements(required), first_unique_elements(optional)
+
+
+def extract_uses_libs_xml(xml):
+ """Extract <uses-library> tags from the manifest."""
+
+ manifest = parse_manifest(xml)
+ elems = get_children_with_tag(manifest, 'application')
+ application = elems[0] if len(elems) == 1 else None
+ if len(elems) > 1:
+ raise RuntimeError('found multiple <application> tags')
+ elif not elems:
+ if uses_libraries or optional_uses_libraries:
+ raise ManifestMismatchError('no <application> tag found')
+ return
libs = get_children_with_tag(application, 'uses-library')
- uses_libraries = [uses_library_name(x) for x in libs if uses_library_required(x)]
- optional_uses_libraries = [uses_library_name(x) for x in libs if not uses_library_required(x)]
+ required = [uses_library_name(x) for x in libs if uses_library_required(x)]
+ optional = [uses_library_name(x) for x in libs if not uses_library_required(x)]
- return first_unique_elements(uses_libraries), first_unique_elements(optional_uses_libraries)
+ return first_unique_elements(required), first_unique_elements(optional)
def first_unique_elements(l):
@@ -167,16 +173,34 @@
return (required.value == 'true') if required is not None else True
-def extract_target_sdk_version(doc):
+def extract_target_sdk_version(manifest, is_apk = False):
"""Returns the targetSdkVersion from the manifest.
Args:
- doc: The XML document.
- Raises:
- RuntimeError: invalid manifest
+ manifest: manifest (either parsed XML or aapt dump of APK)
+ is_apk: if the manifest comes from an APK or an XML file
"""
+ if is_apk:
+ return extract_target_sdk_version_apk(manifest)
+ else:
+ return extract_target_sdk_version_xml(manifest)
- manifest = parse_manifest(doc)
+
+def extract_target_sdk_version_apk(badging):
+ """Extract targetSdkVersion tags from the manifest of an APK."""
+
+ pattern = re.compile("^targetSdkVersion?:'(.*)'$", re.MULTILINE)
+
+ for match in re.finditer(pattern, badging):
+ return match.group(1)
+
+ raise RuntimeError('cannot find targetSdkVersion in the manifest')
+
+
+def extract_target_sdk_version_xml(xml):
+ """Extract targetSdkVersion tags from the manifest."""
+
+ manifest = parse_manifest(xml)
# Get or insert the uses-sdk element
uses_sdk = get_children_with_tag(manifest, 'uses-sdk')
@@ -203,14 +227,22 @@
try:
args = parse_args()
- doc = minidom.parse(args.input)
+ # The input can be either an XML manifest or an APK, they are parsed and
+ # processed in different ways.
+ is_apk = args.input.endswith('.apk')
+ if is_apk:
+ aapt = args.aapt if args.aapt != None else "aapt"
+ manifest = subprocess.check_output([aapt, "dump", "badging", args.input])
+ else:
+ manifest = minidom.parse(args.input)
if args.enforce_uses_libraries:
# Check if the <uses-library> lists in the build system agree with those
# in the manifest. Raise an exception on mismatch, unless the script was
# passed a special parameter to suppress exceptions.
- errmsg = enforce_uses_libraries(doc, args.uses_libraries,
- args.optional_uses_libraries, args.enforce_uses_libraries_relax)
+ errmsg = enforce_uses_libraries(manifest, args.uses_libraries,
+ args.optional_uses_libraries, args.enforce_uses_libraries_relax,
+ is_apk)
# Create a status file that is empty on success, or contains an error
# message on failure. When exceptions are suppressed, dexpreopt command
@@ -221,11 +253,16 @@
f.write("%s\n" % errmsg)
if args.extract_target_sdk_version:
- print(extract_target_sdk_version(doc))
+ print(extract_target_sdk_version(manifest, is_apk))
if args.output:
+ # XML output is supposed to be written only when this script is invoked
+ # with XML input manifest, not with an APK.
+ if is_apk:
+ raise RuntimeError('cannot save APK manifest as XML')
+
with open(args.output, 'wb') as f:
- write_xml(f, doc)
+ write_xml(f, manifest)
# pylint: disable=broad-except
except Exception as err:
diff --git a/scripts/manifest_check_test.py b/scripts/manifest_check_test.py
index 56c2d9e..635ba9d 100755
--- a/scripts/manifest_check_test.py
+++ b/scripts/manifest_check_test.py
@@ -25,28 +25,38 @@
sys.dont_write_bytecode = True
-def uses_library(name, attr=''):
+def uses_library_xml(name, attr=''):
return '<uses-library android:name="%s"%s />' % (name, attr)
-def required(value):
+def required_xml(value):
return ' android:required="%s"' % ('true' if value else 'false')
+def uses_library_apk(name, sfx=''):
+ return "uses-library%s:'%s'" % (sfx, name)
+
+
+def required_apk(value):
+ return '' if value else '-not-required'
+
+
class EnforceUsesLibrariesTest(unittest.TestCase):
"""Unit tests for add_extract_native_libs function."""
- def run_test(self, input_manifest, uses_libraries=None, optional_uses_libraries=None):
- doc = minidom.parseString(input_manifest)
+ def run_test(self, xml, apk, uses_libraries=[], optional_uses_libraries=[]):
+ doc = minidom.parseString(xml)
try:
relax = False
manifest_check.enforce_uses_libraries(doc, uses_libraries,
- optional_uses_libraries, relax)
+ optional_uses_libraries, relax, is_apk=False)
+ manifest_check.enforce_uses_libraries(apk, uses_libraries,
+ optional_uses_libraries, relax, is_apk=True)
return True
except manifest_check.ManifestMismatchError:
return False
- manifest_tmpl = (
+ xml_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
' <application>\n'
@@ -54,115 +64,155 @@
' </application>\n'
'</manifest>\n')
+ apk_tmpl = (
+ "package: name='com.google.android.something' versionCode='100'\n"
+ "sdkVersion:'29'\n"
+ "targetSdkVersion:'29'\n"
+ "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n"
+ "%s\n"
+ "densities: '160' '240' '320' '480' '640' '65534")
+
def test_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo'))
- matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ xml = self.xml_tmpl % (uses_library_xml('foo'))
+ apk = self.apk_tmpl % (uses_library_apk('foo'))
+ matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertTrue(matches)
def test_uses_library_required(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo', required(True)))
- matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(True)))
+ apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(True)))
+ matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertTrue(matches)
def test_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
- matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
+ apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
+ matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
self.assertTrue(matches)
def test_expected_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
- matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
+ apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
+ matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertFalse(matches)
def test_expected_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo'))
- matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ xml = self.xml_tmpl % (uses_library_xml('foo'))
+ apk = self.apk_tmpl % (uses_library_apk('foo'))
+ matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
self.assertFalse(matches)
def test_missing_uses_library(self):
- manifest_input = self.manifest_tmpl % ('')
- matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ xml = self.xml_tmpl % ('')
+ apk = self.apk_tmpl % ('')
+ matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertFalse(matches)
def test_missing_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % ('')
- matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ xml = self.xml_tmpl % ('')
+ apk = self.apk_tmpl % ('')
+ matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
self.assertFalse(matches)
def test_extra_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo'))
- matches = self.run_test(manifest_input)
+ xml = self.xml_tmpl % (uses_library_xml('foo'))
+ apk = self.apk_tmpl % (uses_library_xml('foo'))
+ matches = self.run_test(xml, apk)
self.assertFalse(matches)
def test_extra_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % (uses_library('foo', required(False)))
- matches = self.run_test(manifest_input)
+ xml = self.xml_tmpl % (uses_library_xml('foo', required_xml(False)))
+ apk = self.apk_tmpl % (uses_library_apk('foo', required_apk(False)))
+ matches = self.run_test(xml, apk)
self.assertFalse(matches)
def test_multiple_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
- uses_library('bar')]))
- matches = self.run_test(manifest_input, uses_libraries=['foo', 'bar'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
+ uses_library_xml('bar')]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
+ uses_library_apk('bar')]))
+ matches = self.run_test(xml, apk, uses_libraries=['foo', 'bar'])
self.assertTrue(matches)
def test_multiple_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
- uses_library('bar', required(False))]))
- matches = self.run_test(manifest_input, optional_uses_libraries=['foo', 'bar'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
+ uses_library_xml('bar', required_xml(False))]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
+ uses_library_apk('bar', required_apk(False))]))
+ matches = self.run_test(xml, apk, optional_uses_libraries=['foo', 'bar'])
self.assertTrue(matches)
def test_order_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
- uses_library('bar')]))
- matches = self.run_test(manifest_input, uses_libraries=['bar', 'foo'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
+ uses_library_xml('bar')]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
+ uses_library_apk('bar')]))
+ matches = self.run_test(xml, apk, uses_libraries=['bar', 'foo'])
self.assertFalse(matches)
def test_order_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
- uses_library('bar', required(False))]))
- matches = self.run_test(manifest_input, optional_uses_libraries=['bar', 'foo'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
+ uses_library_xml('bar', required_xml(False))]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
+ uses_library_apk('bar', required_apk(False))]))
+ matches = self.run_test(xml, apk, optional_uses_libraries=['bar', 'foo'])
self.assertFalse(matches)
def test_duplicate_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
- uses_library('foo')]))
- matches = self.run_test(manifest_input, uses_libraries=['foo'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
+ uses_library_xml('foo')]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
+ uses_library_apk('foo')]))
+ matches = self.run_test(xml, apk, uses_libraries=['foo'])
self.assertTrue(matches)
def test_duplicate_optional_uses_library(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo', required(False)),
- uses_library('foo', required(False))]))
- matches = self.run_test(manifest_input, optional_uses_libraries=['foo'])
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo', required_xml(False)),
+ uses_library_xml('foo', required_xml(False))]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo', required_apk(False)),
+ uses_library_apk('foo', required_apk(False))]))
+ matches = self.run_test(xml, apk, optional_uses_libraries=['foo'])
self.assertTrue(matches)
def test_mixed(self):
- manifest_input = self.manifest_tmpl % ('\n'.join([uses_library('foo'),
- uses_library('bar', required(False))]))
- matches = self.run_test(manifest_input, uses_libraries=['foo'],
+ xml = self.xml_tmpl % ('\n'.join([uses_library_xml('foo'),
+ uses_library_xml('bar', required_xml(False))]))
+ apk = self.apk_tmpl % ('\n'.join([uses_library_apk('foo'),
+ uses_library_apk('bar', required_apk(False))]))
+ matches = self.run_test(xml, apk, uses_libraries=['foo'],
optional_uses_libraries=['bar'])
self.assertTrue(matches)
class ExtractTargetSdkVersionTest(unittest.TestCase):
- def test_target_sdk_version(self):
- manifest = (
- '<?xml version="1.0" encoding="utf-8"?>\n'
- '<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="29" />\n'
- '</manifest>\n')
- doc = minidom.parseString(manifest)
- target_sdk_version = manifest_check.extract_target_sdk_version(doc)
- self.assertEqual(target_sdk_version, '29')
+ def run_test(self, xml, apk, version):
+ doc = minidom.parseString(xml)
+ v = manifest_check.extract_target_sdk_version(doc, is_apk=False)
+ self.assertEqual(v, version)
+ v = manifest_check.extract_target_sdk_version(apk, is_apk=True)
+ self.assertEqual(v, version)
- def test_min_sdk_version(self):
- manifest = (
+ xml_tmpl = (
'<?xml version="1.0" encoding="utf-8"?>\n'
'<manifest xmlns:android="http://schemas.android.com/apk/res/android">\n'
- ' <uses-sdk android:minSdkVersion="28" />\n'
+ ' <uses-sdk android:minSdkVersion="28" android:targetSdkVersion="%s" />\n'
'</manifest>\n')
- doc = minidom.parseString(manifest)
- target_sdk_version = manifest_check.extract_target_sdk_version(doc)
- self.assertEqual(target_sdk_version, '28')
+
+ apk_tmpl = (
+ "package: name='com.google.android.something' versionCode='100'\n"
+ "sdkVersion:'28'\n"
+ "targetSdkVersion:'%s'\n"
+ "uses-permission: name='android.permission.ACCESS_NETWORK_STATE'\n")
+
+ def test_targert_sdk_version_28(self):
+ xml = self.xml_tmpl % "28"
+ apk = self.apk_tmpl % "28"
+ self.run_test(xml, apk, "28")
+
+ def test_targert_sdk_version_29(self):
+ xml = self.xml_tmpl % "29"
+ apk = self.apk_tmpl % "29"
+ self.run_test(xml, apk, "29")
if __name__ == '__main__':
unittest.main(verbosity=2)
diff --git a/sdk/Android.bp b/sdk/Android.bp
index 8a3119c..6e49c6d 100644
--- a/sdk/Android.bp
+++ b/sdk/Android.bp
@@ -20,6 +20,7 @@
"update.go",
],
testSrcs: [
+ "boot_image_sdk_test.go",
"bp_test.go",
"cc_sdk_test.go",
"exports_test.go",
diff --git a/sdk/boot_image_sdk_test.go b/sdk/boot_image_sdk_test.go
new file mode 100644
index 0000000..9805a6a
--- /dev/null
+++ b/sdk/boot_image_sdk_test.go
@@ -0,0 +1,62 @@
+// Copyright (C) 2021 The Android Open Source Project
+//
+// 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 sdk
+
+import "testing"
+
+func TestSnapshotWithBootImage(t *testing.T) {
+ result := testSdkWithJava(t, `
+ sdk {
+ name: "mysdk",
+ boot_images: ["mybootimage"],
+ }
+
+ boot_image {
+ name: "mybootimage",
+ image_name: "art",
+ }
+ `)
+
+ CheckSnapshot(t, result, "mysdk", "",
+ checkUnversionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_boot_image {
+ name: "mybootimage",
+ prefer: false,
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ image_name: "art",
+}
+`),
+ checkVersionedAndroidBpContents(`
+// This is auto-generated. DO NOT EDIT.
+
+prebuilt_boot_image {
+ name: "mysdk_mybootimage@current",
+ sdk_member_name: "mybootimage",
+ visibility: ["//visibility:public"],
+ apex_available: ["//apex_available:platform"],
+ image_name: "art",
+}
+
+sdk_snapshot {
+ name: "mysdk@current",
+ visibility: ["//visibility:public"],
+ boot_images: ["mysdk_mybootimage@current"],
+}
+`),
+ checkAllCopyRules(""))
+}
diff --git a/sdk/bp_test.go b/sdk/bp_test.go
index a7164a5..2bd8a43 100644
--- a/sdk/bp_test.go
+++ b/sdk/bp_test.go
@@ -54,26 +54,25 @@
return str
}
-func checkPropertySetFixture(h android.TestHelper, val interface{}, hasTags bool) {
+func checkPropertySetFixture(t *testing.T, val interface{}, hasTags bool) {
set := val.(*bpPropertySet)
- h.AssertDeepEquals("wrong x value", "taxi", set.getValue("x"))
- h.AssertDeepEquals("wrong y value", 1729, set.getValue("y"))
+ android.AssertDeepEquals(t, "wrong x value", "taxi", set.getValue("x"))
+ android.AssertDeepEquals(t, "wrong y value", 1729, set.getValue("y"))
subset := set.getValue("sub").(*bpPropertySet)
- h.AssertDeepEquals("wrong sub.x value", "taxi", subset.getValue("x"))
- h.AssertDeepEquals("wrong sub.y value", 1729, subset.getValue("y"))
+ android.AssertDeepEquals(t, "wrong sub.x value", "taxi", subset.getValue("x"))
+ android.AssertDeepEquals(t, "wrong sub.y value", 1729, subset.getValue("y"))
if hasTags {
- h.AssertDeepEquals("wrong y tag", "tag_y", set.getTag("y"))
- h.AssertDeepEquals("wrong sub.x tag", "tag_x", subset.getTag("x"))
+ android.AssertDeepEquals(t, "wrong y tag", "tag_y", set.getTag("y"))
+ android.AssertDeepEquals(t, "wrong sub.x tag", "tag_x", subset.getTag("x"))
} else {
- h.AssertDeepEquals("wrong y tag", nil, set.getTag("y"))
- h.AssertDeepEquals("wrong sub.x tag", nil, subset.getTag("x"))
+ android.AssertDeepEquals(t, "wrong y tag", nil, set.getTag("y"))
+ android.AssertDeepEquals(t, "wrong sub.x tag", nil, subset.getTag("x"))
}
}
func TestAddPropertySimple(t *testing.T) {
- h := android.TestHelper{t}
set := newPropertySet()
for name, val := range map[string]interface{}{
"x": "taxi",
@@ -83,16 +82,15 @@
"arr": []string{"a", "b", "c"},
} {
set.AddProperty(name, val)
- h.AssertDeepEquals("wrong value", val, set.getValue(name))
+ android.AssertDeepEquals(t, "wrong value", val, set.getValue(name))
}
- h.AssertPanic("adding x again should panic",
+ android.AssertPanic(t, "adding x again should panic",
func() { set.AddProperty("x", "taxi") })
- h.AssertPanic("adding arr again should panic",
+ android.AssertPanic(t, "adding arr again should panic",
func() { set.AddProperty("arr", []string{"d"}) })
}
func TestAddPropertySubset(t *testing.T) {
- h := android.TestHelper{t}
getFixtureMap := map[string]func() interface{}{
"property set": propertySetFixture,
"property struct": propertyStructFixture,
@@ -103,8 +101,8 @@
t.Run(name, func(t *testing.T) {
set := propertySetFixture().(*bpPropertySet)
set.AddProperty("new", getFixture())
- checkPropertySetFixture(h, set, true)
- checkPropertySetFixture(h, set.getValue("new"), name == "property set")
+ checkPropertySetFixture(t, set, true)
+ checkPropertySetFixture(t, set.getValue("new"), name == "property set")
})
}
})
@@ -118,40 +116,38 @@
subset.AddPropertySet("sub")
set.AddProperty("sub", getFixture())
merged := set.getValue("sub").(*bpPropertySet)
- h.AssertDeepEquals("wrong flag value", false, merged.getValue("flag"))
- checkPropertySetFixture(h, merged, name == "property set")
+ android.AssertDeepEquals(t, "wrong flag value", false, merged.getValue("flag"))
+ checkPropertySetFixture(t, merged, name == "property set")
})
}
})
t.Run("add conflicting subset", func(t *testing.T) {
set := propertySetFixture().(*bpPropertySet)
- h.AssertPanic("adding x again should panic",
+ android.AssertPanic(t, "adding x again should panic",
func() { set.AddProperty("x", propertySetFixture()) })
})
t.Run("add non-pointer struct", func(t *testing.T) {
set := propertySetFixture().(*bpPropertySet)
str := propertyStructFixture().(*propertyStruct)
- h.AssertPanic("adding a non-pointer struct should panic",
+ android.AssertPanic(t, "adding a non-pointer struct should panic",
func() { set.AddProperty("new", *str) })
})
}
func TestAddPropertySetNew(t *testing.T) {
- h := android.TestHelper{t}
set := newPropertySet()
subset := set.AddPropertySet("sub")
subset.AddProperty("new", "d^^b")
- h.AssertDeepEquals("wrong sub.new value", "d^^b", set.getValue("sub").(*bpPropertySet).getValue("new"))
+ android.AssertDeepEquals(t, "wrong sub.new value", "d^^b", set.getValue("sub").(*bpPropertySet).getValue("new"))
}
func TestAddPropertySetExisting(t *testing.T) {
- h := android.TestHelper{t}
set := propertySetFixture().(*bpPropertySet)
subset := set.AddPropertySet("sub")
subset.AddProperty("new", "d^^b")
- h.AssertDeepEquals("wrong sub.new value", "d^^b", set.getValue("sub").(*bpPropertySet).getValue("new"))
+ android.AssertDeepEquals(t, "wrong sub.new value", "d^^b", set.getValue("sub").(*bpPropertySet).getValue("new"))
}
type removeFredTransformation struct {
@@ -180,9 +176,6 @@
}
func TestTransformRemoveProperty(t *testing.T) {
-
- helper := android.TestHelper{t}
-
set := newPropertySet()
set.AddProperty("name", "name")
set.AddProperty("fred", "12")
@@ -191,13 +184,10 @@
contents := &generatedContents{}
outputPropertySet(contents, set)
- helper.AssertTrimmedStringEquals("removing property failed", "name: \"name\",\n", contents.content.String())
+ android.AssertTrimmedStringEquals(t, "removing property failed", "name: \"name\",\n", contents.content.String())
}
func TestTransformRemovePropertySet(t *testing.T) {
-
- helper := android.TestHelper{t}
-
set := newPropertySet()
set.AddProperty("name", "name")
set.AddPropertySet("fred")
@@ -206,5 +196,5 @@
contents := &generatedContents{}
outputPropertySet(contents, set)
- helper.AssertTrimmedStringEquals("removing property set failed", "name: \"name\",\n", contents.content.String())
+ android.AssertTrimmedStringEquals(t, "removing property set failed", "name: \"name\",\n", contents.content.String())
}
diff --git a/sdk/cc_sdk_test.go b/sdk/cc_sdk_test.go
index 6da135a..a2539c9 100644
--- a/sdk/cc_sdk_test.go
+++ b/sdk/cc_sdk_test.go
@@ -21,7 +21,7 @@
"android/soong/cc"
)
-var ccTestFs = map[string][]byte{
+var ccTestFs = android.MockFS{
"Test.cpp": nil,
"myinclude/Test.h": nil,
"myinclude-android/AndroidTest.h": nil,
@@ -32,7 +32,7 @@
"some/where/stubslib.map.txt": nil,
}
-func testSdkWithCc(t *testing.T, bp string) *testSdkResult {
+func testSdkWithCc(t *testing.T, bp string) *android.TestResult {
t.Helper()
return testSdkWithFs(t, bp, ccTestFs)
}
@@ -101,7 +101,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -353,7 +353,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -440,7 +440,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAllCopyRules(`
myinclude/Test.h -> include/myinclude/Test.h
.intermediates/mynativelib1/android_arm64_armv8-a_shared/mynativelib1.so -> arm64/lib/mynativelib1.so
@@ -486,7 +486,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -556,7 +556,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -615,7 +615,7 @@
}
`)
- CheckSnapshot(result, "mymodule_exports", "",
+ CheckSnapshot(t, result, "mymodule_exports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -700,7 +700,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -808,7 +808,15 @@
}
func TestSnapshotWithSingleHostOsType(t *testing.T) {
- ctx, config := testSdkContext(`
+ result := sdkFixtureFactory.Extend(
+ ccTestFs.AddToFixture(),
+ cc.PrepareForTestOnLinuxBionic,
+ android.FixtureModifyConfig(func(config android.Config) {
+ config.Targets[android.LinuxBionic] = []android.Target{
+ {android.LinuxBionic, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", false},
+ }
+ }),
+ ).RunTestWithBp(t, `
cc_defaults {
name: "mydefaults",
device_supported: false,
@@ -849,11 +857,9 @@
],
stl: "none",
}
- `, ccTestFs, []android.OsType{android.LinuxBionic})
+ `)
- result := runTests(t, ctx, config)
-
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -991,7 +997,7 @@
}
`)
- CheckSnapshot(result, "mymodule_exports", "",
+ CheckSnapshot(t, result, "mymodule_exports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1099,7 +1105,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1200,7 +1206,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1297,7 +1303,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1424,7 +1430,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1552,7 +1558,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1615,7 +1621,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1729,7 +1735,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1843,7 +1849,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1940,7 +1946,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1978,7 +1984,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2080,7 +2086,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2112,7 +2118,6 @@
},
}
`),
- // Verifi
checkVersionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2193,7 +2198,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2266,7 +2271,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2377,7 +2382,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2430,7 +2435,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2543,7 +2548,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -2658,7 +2663,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkUnversionedAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
diff --git a/sdk/exports_test.go b/sdk/exports_test.go
index 54a40d2..fd7741c 100644
--- a/sdk/exports_test.go
+++ b/sdk/exports_test.go
@@ -42,7 +42,7 @@
"package/Android.bp": []byte(packageBp),
})
- CheckSnapshot(result, "myexports", "package",
+ CheckSnapshot(t, result, "myexports", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
diff --git a/sdk/java_sdk_test.go b/sdk/java_sdk_test.go
index ef8e4a0..f4e9380 100644
--- a/sdk/java_sdk_test.go
+++ b/sdk/java_sdk_test.go
@@ -17,10 +17,11 @@
import (
"testing"
+ "android/soong/android"
"android/soong/java"
)
-func testSdkWithJava(t *testing.T, bp string) *testSdkResult {
+func testSdkWithJava(t *testing.T, bp string) *android.TestResult {
t.Helper()
fs := map[string][]byte{
@@ -127,7 +128,7 @@
// Make sure that the mysdk module depends on "sdkmember" and not "prebuilt_sdkmember".
java.CheckModuleDependencies(t, result.TestContext, "mysdk", "android_common", []string{"sdkmember"})
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`// This is auto-generated. DO NOT EDIT.
java_import {
@@ -255,7 +256,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -312,7 +313,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -369,7 +370,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -440,7 +441,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -496,7 +497,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -551,7 +552,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -607,7 +608,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -662,7 +663,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -731,7 +732,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -827,7 +828,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -918,7 +919,7 @@
}
`)
- CheckSnapshot(result, "myexports", "",
+ CheckSnapshot(t, result, "myexports", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1032,7 +1033,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1133,7 +1134,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1202,7 +1203,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1274,7 +1275,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1367,7 +1368,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1475,7 +1476,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1563,7 +1564,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -1639,7 +1640,7 @@
}
`)
- CheckSnapshot(result, "mysdk", "",
+ CheckSnapshot(t, result, "mysdk", "",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
diff --git a/sdk/sdk_test.go b/sdk/sdk_test.go
index 65a9001..05d8bdb 100644
--- a/sdk/sdk_test.go
+++ b/sdk/sdk_test.go
@@ -169,7 +169,7 @@
"package/Android.bp": []byte(packageBp),
})
- CheckSnapshot(result, "mysdk", "package",
+ CheckSnapshot(t, result, "mysdk", "package",
checkAndroidBpContents(`
// This is auto-generated. DO NOT EDIT.
@@ -317,9 +317,8 @@
`
result := testSdkWithFs(t, sdk, nil)
- CheckSnapshot(result, "mysdk", "",
- checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`),
- )
+ CheckSnapshot(t, result, "mysdk", "",
+ checkAllOtherCopyRules(`.intermediates/mysdk/common_os/mysdk-current.zip -> mysdk-current.zip`))
}
type EmbeddedPropertiesStruct struct {
@@ -387,12 +386,10 @@
extractor := newCommonValueExtractor(common)
- h := android.TestHelper{t}
-
err := extractor.extractCommonProperties(common, structs)
- h.AssertDeepEquals("unexpected error", nil, err)
+ android.AssertDeepEquals(t, "unexpected error", nil, err)
- h.AssertDeepEquals("common properties not correct",
+ android.AssertDeepEquals(t, "common properties not correct",
&testPropertiesStruct{
name: "common",
private: "",
@@ -410,7 +407,7 @@
},
common)
- h.AssertDeepEquals("updated properties[0] not correct",
+ android.AssertDeepEquals(t, "updated properties[0] not correct",
&testPropertiesStruct{
name: "struct-0",
private: "common",
@@ -428,7 +425,7 @@
},
structs[0])
- h.AssertDeepEquals("updated properties[1] not correct",
+ android.AssertDeepEquals(t, "updated properties[1] not correct",
&testPropertiesStruct{
name: "struct-1",
private: "common",
@@ -462,10 +459,8 @@
extractor := newCommonValueExtractor(common)
- h := android.TestHelper{t}
-
err := extractor.extractCommonProperties(common, structs)
- h.AssertErrorMessageEquals("unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties:
+ android.AssertErrorMessageEquals(t, "unexpected error", `field "S_Common" is not tagged as "arch_variant" but has arch specific properties:
"struct-0" has value "should-be-but-is-not-common0"
"struct-1" has value "should-be-but-is-not-common1"`, err)
}
diff --git a/sdk/testing.go b/sdk/testing.go
index 3fb27ca..a5519f8 100644
--- a/sdk/testing.go
+++ b/sdk/testing.go
@@ -29,10 +29,15 @@
"android/soong/java"
)
-func testSdkContext(bp string, fs map[string][]byte, extraOsTypes []android.OsType) (*android.TestContext, android.Config) {
- extraOsTypes = append(extraOsTypes, android.Android, android.Windows)
+var sdkFixtureFactory = android.NewFixtureFactory(
+ &buildDir,
+ apex.PrepareForTestWithApexBuildComponents,
+ cc.PrepareForTestWithCcDefaultModules,
+ genrule.PrepareForTestWithGenRuleBuildComponents,
+ java.PrepareForTestWithJavaBuildComponents,
+ PrepareForTestWithSdkBuildComponents,
- bp = bp + `
+ android.FixtureAddTextFile("sdk/tests/Android.bp", `
apex_key {
name: "myapex.key",
public_key: "myapex.avbpubkey",
@@ -43,9 +48,9 @@
name: "myapex.cert",
certificate: "myapex",
}
- ` + cc.GatherRequiredDepsForTest(extraOsTypes...)
+ `),
- mockFS := map[string][]byte{
+ android.FixtureMergeMockFs(map[string][]byte{
"build/make/target/product/security": nil,
"apex_manifest.json": nil,
"system/sepolicy/apex/myapex-file_contexts": nil,
@@ -55,113 +60,33 @@
"myapex.pem": nil,
"myapex.x509.pem": nil,
"myapex.pk8": nil,
- }
+ }),
- cc.GatherRequiredFilesForTest(mockFS)
-
- for k, v := range fs {
- mockFS[k] = v
- }
-
- config := android.TestArchConfig(buildDir, nil, bp, mockFS)
-
- // Add windows as a default disable OS to test behavior when some OS variants
- // are disabled.
- config.Targets[android.Windows] = []android.Target{
- {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", true},
- }
-
- for _, extraOsType := range extraOsTypes {
- switch extraOsType {
- case android.LinuxBionic:
- config.Targets[android.LinuxBionic] = []android.Target{
- {android.LinuxBionic, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", false},
- }
+ cc.PrepareForTestOnWindows,
+ android.FixtureModifyConfig(func(config android.Config) {
+ // Add windows as a default disable OS to test behavior when some OS variants
+ // are disabled.
+ config.Targets[android.Windows] = []android.Target{
+ {android.Windows, android.Arch{ArchType: android.X86_64}, android.NativeBridgeDisabled, "", "", true},
}
- }
+ }),
+)
- ctx := android.NewTestArchContext(config)
+var PrepareForTestWithSdkBuildComponents = android.GroupFixturePreparers(
+ android.FixtureRegisterWithContext(registerModuleExportsBuildComponents),
+ android.FixtureRegisterWithContext(registerSdkBuildComponents),
+)
- // Enable androidmk support.
- // * Register the singleton
- // * Configure that we are inside make
- // * Add CommonOS to ensure that androidmk processing works.
- android.RegisterAndroidMkBuildComponents(ctx)
- android.SetKatiEnabledForTests(config)
- config.Targets[android.CommonOS] = []android.Target{
- {android.CommonOS, android.Arch{ArchType: android.Common}, android.NativeBridgeDisabled, "", "", true},
- }
-
- // from android package
- android.RegisterPackageBuildComponents(ctx)
- ctx.RegisterModuleType("filegroup", android.FileGroupFactory)
- ctx.PreArchMutators(android.RegisterVisibilityRuleChecker)
- ctx.PreArchMutators(android.RegisterDefaultsPreArchMutators)
- ctx.PreArchMutators(android.RegisterComponentsMutator)
-
- android.RegisterPrebuiltMutators(ctx)
-
- // Register these after the prebuilt mutators have been registered to match what
- // happens at runtime.
- ctx.PreArchMutators(android.RegisterVisibilityRuleGatherer)
- ctx.PostDepsMutators(android.RegisterVisibilityRuleEnforcer)
-
- // from java package
- java.RegisterRequiredBuildComponentsForTest(ctx)
-
- // from genrule package
- genrule.RegisterGenruleBuildComponents(ctx)
-
- // from cc package
- cc.RegisterRequiredBuildComponentsForTest(ctx)
-
- // from apex package
- ctx.RegisterModuleType("apex", apex.BundleFactory)
- ctx.RegisterModuleType("apex_key", apex.ApexKeyFactory)
- ctx.PostDepsMutators(apex.RegisterPostDepsMutators)
-
- // from this package
- registerModuleExportsBuildComponents(ctx)
- registerSdkBuildComponents(ctx)
-
- ctx.Register()
-
- return ctx, config
-}
-
-func runTests(t *testing.T, ctx *android.TestContext, config android.Config) *testSdkResult {
+func testSdkWithFs(t *testing.T, bp string, fs android.MockFS) *android.TestResult {
t.Helper()
- _, errs := ctx.ParseBlueprintsFiles(".")
- android.FailIfErrored(t, errs)
- _, errs = ctx.PrepareBuildActions(config)
- android.FailIfErrored(t, errs)
- return &testSdkResult{
- TestHelper: android.TestHelper{T: t},
- TestContext: ctx,
- }
-}
-
-func testSdkWithFs(t *testing.T, bp string, fs map[string][]byte) *testSdkResult {
- t.Helper()
- ctx, config := testSdkContext(bp, fs, nil)
- return runTests(t, ctx, config)
+ return sdkFixtureFactory.RunTest(t, fs.AddToFixture(), android.FixtureWithRootAndroidBp(bp))
}
func testSdkError(t *testing.T, pattern, bp string) {
t.Helper()
- ctx, config := testSdkContext(bp, nil, nil)
- _, errs := ctx.ParseFileList(".", []string{"Android.bp"})
- if len(errs) > 0 {
- android.FailIfNoMatchingErrors(t, pattern, errs)
- return
- }
- _, errs = ctx.PrepareBuildActions(config)
- if len(errs) > 0 {
- android.FailIfNoMatchingErrors(t, pattern, errs)
- return
- }
-
- t.Fatalf("missing expected error %q (0 errors are returned)", pattern)
+ sdkFixtureFactory.
+ ExtendWithErrorHandler(android.FixtureExpectsAtLeastOneErrorMatchingPattern(pattern)).
+ RunTestWithBp(t, bp)
}
func ensureListContains(t *testing.T, result []string, expected string) {
@@ -179,23 +104,13 @@
return ret
}
-// Encapsulates result of processing an SDK definition. Provides support for
-// checking the state of the build structures.
-type testSdkResult struct {
- android.TestHelper
- *android.TestContext
-}
-
-func (result *testSdkResult) Module(name string, variant string) android.Module {
- return result.ModuleForTests(name, variant).Module()
-}
-
// Analyse the sdk build rules to extract information about what it is doing.
//
// e.g. find the src/dest pairs from each cp command, the various zip files
// generated, etc.
-func getSdkSnapshotBuildInfo(result *testSdkResult, sdk *sdk) *snapshotBuildInfo {
+func getSdkSnapshotBuildInfo(t *testing.T, result *android.TestResult, sdk *sdk) *snapshotBuildInfo {
info := &snapshotBuildInfo{
+ t: t,
r: result,
androidBpContents: sdk.GetAndroidBpContentsForTests(),
androidUnversionedBpContents: sdk.GetUnversionedAndroidBpContentsForTests(),
@@ -239,7 +154,7 @@
info.intermediateZip = info.outputZip
mergeInput := android.NormalizePathForTesting(bp.Input)
if info.intermediateZip != mergeInput {
- result.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead",
+ t.Errorf("Expected intermediate zip %s to be an input to merge zips but found %s instead",
info.intermediateZip, mergeInput)
}
@@ -263,15 +178,15 @@
// Takes a list of functions which check different facets of the snapshot build rules.
// Allows each test to customize what is checked without duplicating lots of code
// or proliferating check methods of different flavors.
-func CheckSnapshot(result *testSdkResult, name string, dir string, checkers ...snapshotBuildInfoChecker) {
- result.Helper()
+func CheckSnapshot(t *testing.T, result *android.TestResult, name string, dir string, checkers ...snapshotBuildInfoChecker) {
+ t.Helper()
// The sdk CommonOS variant is always responsible for generating the snapshot.
variant := android.CommonOS.Name
sdk := result.Module(name, variant).(*sdk)
- snapshotBuildInfo := getSdkSnapshotBuildInfo(result, sdk)
+ snapshotBuildInfo := getSdkSnapshotBuildInfo(t, result, sdk)
// Check state of the snapshot build.
for _, checker := range checkers {
@@ -283,7 +198,7 @@
if dir != "" {
dir = filepath.Clean(dir) + "/"
}
- result.AssertStringEquals("Snapshot zip file in wrong place",
+ android.AssertStringEquals(t, "Snapshot zip file in wrong place",
fmt.Sprintf(".intermediates/%s%s/%s/%s-current.zip", dir, name, variant, name), actual)
// Populate a mock filesystem with the files that would have been copied by
@@ -294,7 +209,7 @@
}
// Process the generated bp file to make sure it is valid.
- testSdkWithFs(result.T, snapshotBuildInfo.androidBpContents, fs)
+ testSdkWithFs(t, snapshotBuildInfo.androidBpContents, fs)
}
type snapshotBuildInfoChecker func(info *snapshotBuildInfo)
@@ -304,8 +219,8 @@
// Both the expected and actual string are both trimmed before comparing.
func checkAndroidBpContents(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
- info.r.AssertTrimmedStringEquals("Android.bp contents do not match", expected, info.androidBpContents)
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "Android.bp contents do not match", expected, info.androidBpContents)
}
}
@@ -316,8 +231,8 @@
// Both the expected and actual string are both trimmed before comparing.
func checkUnversionedAndroidBpContents(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
- info.r.AssertTrimmedStringEquals("unversioned Android.bp contents do not match", expected, info.androidUnversionedBpContents)
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "unversioned Android.bp contents do not match", expected, info.androidUnversionedBpContents)
}
}
@@ -331,8 +246,8 @@
// Both the expected and actual string are both trimmed before comparing.
func checkVersionedAndroidBpContents(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
- info.r.AssertTrimmedStringEquals("versioned Android.bp contents do not match", expected, info.androidVersionedBpContents)
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "versioned Android.bp contents do not match", expected, info.androidVersionedBpContents)
}
}
@@ -343,27 +258,27 @@
// before comparing.
func checkAllCopyRules(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
- info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.copyRules)
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "Incorrect copy rules", expected, info.copyRules)
}
}
func checkAllOtherCopyRules(expected string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
- info.r.AssertTrimmedStringEquals("Incorrect copy rules", expected, info.otherCopyRules)
+ info.t.Helper()
+ android.AssertTrimmedStringEquals(info.t, "Incorrect copy rules", expected, info.otherCopyRules)
}
}
// Check that the specified paths match the list of zips to merge with the intermediate zip.
func checkMergeZips(expected ...string) snapshotBuildInfoChecker {
return func(info *snapshotBuildInfo) {
- info.r.Helper()
+ info.t.Helper()
if info.intermediateZip == "" {
- info.r.Errorf("No intermediate zip file was created")
+ info.t.Errorf("No intermediate zip file was created")
}
- info.r.AssertDeepEquals("mismatching merge zip files", expected, info.mergeZips)
+ android.AssertDeepEquals(info.t, "mismatching merge zip files", expected, info.mergeZips)
}
}
@@ -373,7 +288,10 @@
// All source/input paths are relative either the build directory. All dest/output paths are
// relative to the snapshot root directory.
type snapshotBuildInfo struct {
- r *testSdkResult
+ t *testing.T
+
+ // The result from RunTest()
+ r *android.TestResult
// The contents of the generated Android.bp file
androidBpContents string
diff --git a/sh/sh_binary_test.go b/sh/sh_binary_test.go
index 7a24168..5887b56 100644
--- a/sh/sh_binary_test.go
+++ b/sh/sh_binary_test.go
@@ -1,44 +1,20 @@
package sh
import (
- "io/ioutil"
"os"
- "path"
"path/filepath"
- "reflect"
"testing"
"android/soong/android"
"android/soong/cc"
)
-var buildDir string
-
-func setUp() {
- var err error
- buildDir, err = ioutil.TempDir("", "soong_sh_test")
- if err != nil {
- panic(err)
- }
-}
-
-func tearDown() {
- os.RemoveAll(buildDir)
-}
-
func TestMain(m *testing.M) {
- run := func() int {
- setUp()
- defer tearDown()
-
- return m.Run()
- }
-
- os.Exit(run())
+ os.Exit(m.Run())
}
var shFixtureFactory = android.NewFixtureFactory(
- &buildDir,
+ nil,
cc.PrepareForTestWithCcBuildComponents,
PrepareForTestWithShBuildComponents,
android.FixtureMergeMockFs(android.MockFS{
@@ -66,7 +42,7 @@
}
func TestShTestSubDir(t *testing.T) {
- ctx, _ := testShBinary(t, `
+ ctx, config := testShBinary(t, `
sh_test {
name: "foo",
src: "test.sh",
@@ -78,16 +54,13 @@
entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
- expectedPath := path.Join(buildDir,
- "../target/product/test_device/data/nativetest64/foo_test")
+ expectedPath := "out/target/product/test_device/data/nativetest64/foo_test"
actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
- if expectedPath != actualPath {
- t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
- }
+ android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
}
func TestShTest(t *testing.T) {
- ctx, _ := testShBinary(t, `
+ ctx, config := testShBinary(t, `
sh_test {
name: "foo",
src: "test.sh",
@@ -103,22 +76,17 @@
entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
- expectedPath := path.Join(buildDir,
- "../target/product/test_device/data/nativetest64/foo")
+ expectedPath := "out/target/product/test_device/data/nativetest64/foo"
actualPath := entries.EntryMap["LOCAL_MODULE_PATH"][0]
- if expectedPath != actualPath {
- t.Errorf("Unexpected LOCAL_MODULE_PATH expected: %q, actual: %q", expectedPath, actualPath)
- }
+ android.AssertStringPathRelativeToTopEquals(t, "LOCAL_MODULE_PATH[0]", config, expectedPath, actualPath)
expectedData := []string{":testdata/data1", ":testdata/sub/data2"}
actualData := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expectedData, actualData) {
- t.Errorf("Unexpected test data expected: %q, actual: %q", expectedData, actualData)
- }
+ android.AssertDeepEquals(t, "LOCAL_TEST_DATA", expectedData, actualData)
}
func TestShTest_dataModules(t *testing.T) {
- ctx, _ := testShBinary(t, `
+ ctx, config := testShBinary(t, `
sh_test {
name: "foo",
src: "test.sh",
@@ -157,22 +125,17 @@
libExt = ".dylib"
}
relocated := variant.Output("relocated/lib64/libbar" + libExt)
- expectedInput := filepath.Join(buildDir, ".intermediates/libbar/"+arch+"_shared/libbar"+libExt)
- if relocated.Input.String() != expectedInput {
- t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
- expectedInput, relocated.Input.String())
- }
+ expectedInput := "out/soong/.intermediates/libbar/" + arch + "_shared/libbar" + libExt
+ android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
mod := variant.Module().(*ShTest)
entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
expectedData := []string{
- filepath.Join(buildDir, ".intermediates/bar", arch, ":bar"),
- filepath.Join(buildDir, ".intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
+ filepath.Join("out/soong/.intermediates/bar", arch, ":bar"),
+ filepath.Join("out/soong/.intermediates/foo", arch, "relocated/:lib64/libbar"+libExt),
}
actualData := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expectedData, actualData) {
- t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
- }
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
}
}
@@ -197,7 +160,7 @@
}
func TestShTestHost_dataDeviceModules(t *testing.T) {
- ctx, _ := testShBinary(t, `
+ ctx, config := testShBinary(t, `
sh_test_host {
name: "foo",
src: "test.sh",
@@ -227,21 +190,16 @@
variant := ctx.ModuleForTests("foo", buildOS+"_x86_64")
relocated := variant.Output("relocated/lib64/libbar.so")
- expectedInput := filepath.Join(buildDir, ".intermediates/libbar/android_arm64_armv8-a_shared/libbar.so")
- if relocated.Input.String() != expectedInput {
- t.Errorf("Unexpected relocation input, expected: %q, actual: %q",
- expectedInput, relocated.Input.String())
- }
+ expectedInput := "out/soong/.intermediates/libbar/android_arm64_armv8-a_shared/libbar.so"
+ android.AssertPathRelativeToTopEquals(t, "relocation input", expectedInput, relocated.Input)
mod := variant.Module().(*ShTest)
entries := android.AndroidMkEntriesForTest(t, ctx, mod)[0]
expectedData := []string{
- filepath.Join(buildDir, ".intermediates/bar/android_arm64_armv8-a/:bar"),
+ "out/soong/.intermediates/bar/android_arm64_armv8-a/:bar",
// libbar has been relocated, and so has a variant that matches the host arch.
- filepath.Join(buildDir, ".intermediates/foo/"+buildOS+"_x86_64/relocated/:lib64/libbar.so"),
+ "out/soong/.intermediates/foo/" + buildOS + "_x86_64/relocated/:lib64/libbar.so",
}
actualData := entries.EntryMap["LOCAL_TEST_DATA"]
- if !reflect.DeepEqual(expectedData, actualData) {
- t.Errorf("Unexpected test data, expected: %q, actual: %q", expectedData, actualData)
- }
+ android.AssertStringPathsRelativeToTopEquals(t, "LOCAL_TEST_DATA", config, expectedData, actualData)
}